Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Udayraj123
GitHub Repository: Udayraj123/OMRChecker
Path: blob/master/src/utils/parsing.py
228 views
1
import re
2
from copy import deepcopy
3
from fractions import Fraction
4
5
from deepmerge import Merger
6
from dotmap import DotMap
7
8
from src.constants import FIELD_LABEL_NUMBER_REGEX
9
from src.defaults import CONFIG_DEFAULTS, TEMPLATE_DEFAULTS
10
from src.schemas.constants import FIELD_STRING_REGEX_GROUPS
11
from src.utils.file import load_json
12
from src.utils.validations import (
13
validate_config_json,
14
validate_evaluation_json,
15
validate_template_json,
16
)
17
18
OVERRIDE_MERGER = Merger(
19
# pass in a list of tuples,with the
20
# strategies you are looking to apply
21
# to each type.
22
[
23
# (list, ["prepend"]),
24
(dict, ["merge"])
25
],
26
# next, choose the fallback strategies,
27
# applied to all other types:
28
["override"],
29
# finally, choose the strategies in
30
# the case where the types conflict:
31
["override"],
32
)
33
34
35
def get_concatenated_response(omr_response, template):
36
# Multi-column/multi-row questions which need to be concatenated
37
concatenated_response = {}
38
for field_label, concatenate_keys in template.custom_labels.items():
39
custom_label = "".join([omr_response[k] for k in concatenate_keys])
40
concatenated_response[field_label] = custom_label
41
42
for field_label in template.non_custom_labels:
43
concatenated_response[field_label] = omr_response[field_label]
44
45
return concatenated_response
46
47
48
def open_config_with_defaults(config_path):
49
user_tuning_config = load_json(config_path)
50
user_tuning_config = OVERRIDE_MERGER.merge(
51
deepcopy(CONFIG_DEFAULTS), user_tuning_config
52
)
53
validate_config_json(user_tuning_config, config_path)
54
# https://github.com/drgrib/dotmap/issues/74
55
return DotMap(user_tuning_config, _dynamic=False)
56
57
58
def open_template_with_defaults(template_path):
59
user_template = load_json(template_path)
60
user_template = OVERRIDE_MERGER.merge(deepcopy(TEMPLATE_DEFAULTS), user_template)
61
validate_template_json(user_template, template_path)
62
return user_template
63
64
65
def open_evaluation_with_validation(evaluation_path):
66
user_evaluation_config = load_json(evaluation_path)
67
validate_evaluation_json(user_evaluation_config, evaluation_path)
68
return user_evaluation_config
69
70
71
def parse_fields(key, fields):
72
parsed_fields = []
73
fields_set = set()
74
for field_string in fields:
75
fields_array = parse_field_string(field_string)
76
current_set = set(fields_array)
77
if not fields_set.isdisjoint(current_set):
78
raise Exception(
79
f"Given field string '{field_string}' has overlapping field(s) with other fields in '{key}': {fields}"
80
)
81
fields_set.update(current_set)
82
parsed_fields.extend(fields_array)
83
return parsed_fields
84
85
86
def parse_field_string(field_string):
87
if "." in field_string:
88
field_prefix, start, end = re.findall(FIELD_STRING_REGEX_GROUPS, field_string)[
89
0
90
]
91
start, end = int(start), int(end)
92
if start >= end:
93
raise Exception(
94
f"Invalid range in fields string: '{field_string}', start: {start} is not less than end: {end}"
95
)
96
return [
97
f"{field_prefix}{field_number}" for field_number in range(start, end + 1)
98
]
99
else:
100
return [field_string]
101
102
103
def custom_sort_output_columns(field_label):
104
label_prefix, label_suffix = re.findall(FIELD_LABEL_NUMBER_REGEX, field_label)[0]
105
return [label_prefix, int(label_suffix) if len(label_suffix) > 0 else 0]
106
107
108
def parse_float_or_fraction(result):
109
if type(result) == str and "/" in result:
110
result = float(Fraction(result))
111
else:
112
result = float(result)
113
return result
114
115