diff --git a/src/caosadvancedtools/table_json_conversion/fill_xlsx.py b/src/caosadvancedtools/table_json_conversion/fill_xlsx.py index 60b5c96c7de141b1ecb12254e6928252fe4a9f5c..585bc6bf283083b343c85cdbe3d0d9dbdeb9decc 100644 --- a/src/caosadvancedtools/table_json_conversion/fill_xlsx.py +++ b/src/caosadvancedtools/table_json_conversion/fill_xlsx.py @@ -206,6 +206,7 @@ class TemplateFiller: Index the sheets by all path arrays leading to them. Also create a simple column index by column type and path. + This method creates and populates the dict ``self._sheet_index``. """ self._sheet_index = {} for sheetname in self._workbook.sheetnames: @@ -227,7 +228,8 @@ class TemplateFiller: path.append(col[path_idx].value) # col_key = p2s([col[coltype_idx].value] + path) # col_index[col_key] = SimpleNamespace(column=col, col_index=col_idx) - if col[coltype_idx].value not in [ColumnType.SCALAR.name, ColumnType.LIST.name]: + if col[coltype_idx].value not in [ColumnType.SCALAR.name, ColumnType.LIST.name, + ColumnType.MULTIPLE_CHOICE.name]: continue path_str = p2s(path) @@ -308,16 +310,20 @@ out: union[dict, None] # collecting the data assert isinstance(content, list) - if len(content) > 1: - content = [ILLEGAL_CHARACTERS_RE.sub("", str(x)) for x in content] - value = ";".join(content) # TODO we need escaping of values - else: - value = content[0] - if isinstance(value, str): - value = ILLEGAL_CHARACTERS_RE.sub("", value) - path_str = p2s(path) - assert path_str not in insertables - insertables[path_str] = value + to_insert = self._try_multiple_choice(path, values=content) + if not to_insert: + if len(content) > 1: + content = [ILLEGAL_CHARACTERS_RE.sub("", str(x)) for x in content] + value = ";".join(content) # TODO we need escaping of values + else: + value = content[0] + if isinstance(value, str): + value = ILLEGAL_CHARACTERS_RE.sub("", value) + + path_str = p2s(path) + assert path_str not in insertables + to_insert = {path_str: value} + insertables.update(to_insert) if only_collect_insertables: return insertables if not current_path: # Top level returns, because there are only sheets for the children. @@ -353,6 +359,40 @@ out: union[dict, None] return None + def _try_multiple_choice(self, path: list[str], values: list[str]) -> Optional[dict[str, str]]: + """Try to create sheet content for a multiple choice property. + +Parameters +---------- +path: list[str] + The Path to this property. +values: list[str] + A list of possible choices, should be unique. + +Returns +------- +to_insert: Optional[dict[str, str]] + A path-value dict. None if this doesn't seem to be a multiple choice data set. + """ + try: + assert len(set(values)) == len(values) + to_insert = {} + found_sheet = None + for value in values: + assert isinstance(value, str) + path_str = p2s(path + [value]) + assert path_str in self._sheet_index + sheet_meta = self._sheet_index[path_str] + # All matches shall be on the same sheet + assert found_sheet is None or found_sheet == sheet_meta.sheetname + found_sheet = sheet_meta.sheetname + # Correct type + assert sheet_meta.col_type == ColumnType.MULTIPLE_CHOICE.name + to_insert[path_str] = "x" + except AssertionError: + return None + return to_insert + def fill_template(data: Union[dict, str, TextIO], template: str, result: str, validation_schema: Union[dict, str, TextIO] = None) -> None: diff --git a/unittests/table_json_conversion/data/multiple_choice_data.json b/unittests/table_json_conversion/data/multiple_choice_data.json new file mode 100644 index 0000000000000000000000000000000000000000..1f14911ea79e8d78a452bb221f693d1a01cce744 --- /dev/null +++ b/unittests/table_json_conversion/data/multiple_choice_data.json @@ -0,0 +1,11 @@ +{ + "Training": { + "name": "Super Skill Training", + "date": "2024-04-17", + "skills": [ + "Planning", + "Evaluation" + ], + "exam_types": [] + } +} diff --git a/unittests/table_json_conversion/data/multiple_choice_data.xlsx b/unittests/table_json_conversion/data/multiple_choice_data.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..28cf4007d8a1a061235863d12e5bdc5b5747f386 Binary files /dev/null and b/unittests/table_json_conversion/data/multiple_choice_data.xlsx differ diff --git a/unittests/table_json_conversion/data/multiple_choice_schema.json b/unittests/table_json_conversion/data/multiple_choice_schema.json index 75de127e4115eca6047d8fd4acd76f668f83d845..71bf0379aba4ad6f8510581ba0defadb81a66609 100644 --- a/unittests/table_json_conversion/data/multiple_choice_schema.json +++ b/unittests/table_json_conversion/data/multiple_choice_schema.json @@ -35,6 +35,16 @@ ] }, "uniqueItems": true + }, + "exam_types": { + "type": "array", + "items": { + "enum": [ + "Oral", + "Written" + ] + }, + "uniqueItems": true } } } diff --git a/unittests/table_json_conversion/data/multiple_choice_template.xlsx b/unittests/table_json_conversion/data/multiple_choice_template.xlsx index 1b4abaadb5b9a2218340f848d93cd2fbf8948908..e523506201ee7301dfa6f814e0315c01b95b08ee 100644 Binary files a/unittests/table_json_conversion/data/multiple_choice_template.xlsx and b/unittests/table_json_conversion/data/multiple_choice_template.xlsx differ diff --git a/unittests/table_json_conversion/test_fill_xlsx.py b/unittests/table_json_conversion/test_fill_xlsx.py index 946336da721f7c9affd5c553ccbb38cb46217eef..1315bd9fe06196ba5df31d34182293887d5a2bb1 100644 --- a/unittests/table_json_conversion/test_fill_xlsx.py +++ b/unittests/table_json_conversion/test_fill_xlsx.py @@ -138,6 +138,10 @@ def test_fill_xlsx(): template_file=rfp("data/simple_template.xlsx"), known_good=rfp("data/simple_data_ascii_chars.xlsx"), schema=rfp("data/simple_schema.json")) + fill_and_compare(json_file=rfp("data/multiple_choice_data.json"), + template_file=rfp("data/multiple_choice_template.xlsx"), + known_good=rfp("data/multiple_choice_data.xlsx"), + schema=rfp("data/multiple_choice_schema.json")) def test_errors():