diff --git a/src/caosadvancedtools/table_json_conversion/table_generator.py b/src/caosadvancedtools/table_json_conversion/table_generator.py index f0e8f6c6d816e4d0ea76e7d776d351e4a5d8ecb5..8c1952ebfcd815f759ec3e12e07f788ae42c1834 100644 --- a/src/caosadvancedtools/table_json_conversion/table_generator.py +++ b/src/caosadvancedtools/table_json_conversion/table_generator.py @@ -103,7 +103,7 @@ class TableTemplateGenerator(ABC): if foreign_keys is None: foreign_keys = {} # here, we treat the top level - # sheets[sheetname][colname]= (COL_TYPE, [path]) + # sheets[sheetname][colname]= (COL_TYPE, description, [path]) sheets: dict[str, dict[str, tuple[str, list]]] = {} if "properties" not in schema: raise ValueError("Inappropriate JSON schema: The following part should contain " @@ -139,24 +139,42 @@ class TableTemplateGenerator(ABC): return selected_keys def _treat_schema_element(self, schema: dict, sheets: dict = None, path: list = None, - foreign_keys: dict = None, level_in_sheet_name: int = 1 - ) -> dict[str, tuple[str, list]]: - """ recursively transforms elements from the schema into column definitions """ + foreign_keys: dict = None, level_in_sheet_name: int = 1, + array_paths: list = None + ) -> dict[str, tuple[str, str, list]]: + """ recursively transforms elements from the schema into column definitions + + sheets is modified in place. + Returns + ------- + + dict + describing the columns; see doc string of _generate_sheets_from_schema + """ if not ("type" in schema or "enum" in schema or "oneOf" in schema or "anyOf" in schema): raise ValueError("Inappropriate JSON schema: The following part should contain the " f"'type' key:\n{schema}\n") + if array_paths is None: + array_paths = [path] + ctype = ColumnType.SCALAR # if it is an array, value defs are in 'items' if 'type' in schema and schema['type'] == 'array': - if 'type' in schema['items'] and schema['items']['type'] == 'object' and len(path) > 1: # list of references; special treatment + if ('type' in schema['items'] and schema['items']['type'] == 'object' + and len(path) > 1): # list of references; special treatment # we add a new sheet - sheets[path[-1]] = self._treat_schema_element(schema['items'], sheets, path, - foreign_keys, - len(path)) - for c in self._get_foreign_keys(foreign_keys, path[:-1]): - sheets[path[-1]].update({c: (ColumnType.FOREIGN, f"see sheet '{path[0]}'", path[:-1]+[c])}) + sheetname = ".".join(path) + sheets[sheetname] = self._treat_schema_element( + schema['items'], sheets, path, foreign_keys, len(path), + array_paths=array_paths+[path]) + print("Sel", path) + for p in array_paths: + keys = self._get_foreign_keys(foreign_keys, p) + for k in keys: + print(k, p) + sheets[sheetname].update({k: (ColumnType.FOREIGN, f"see sheet '{path[0]}'", p+[k])}) # columns are added to the new sheet, thus we do not return columns return {} else: @@ -175,7 +193,7 @@ class TableTemplateGenerator(ABC): for pname in schema["properties"].keys(): cols.update(self._treat_schema_element( schema["properties"][pname], sheets, path+[pname], foreign_keys, - level_in_sheet_name)) + level_in_sheet_name, array_paths=array_paths)) return cols else: description = schema['description'] if 'description' in schema else None diff --git a/unittests/table_json_conversion/test_table_template_generator.py b/unittests/table_json_conversion/test_table_template_generator.py index 34e0ac750a0282e1eb7426352e5baa0c08cfb9a2..47fb5d21f68f9e99ba5d6bdd3e2bbf10406f1fc2 100644 --- a/unittests/table_json_conversion/test_table_template_generator.py +++ b/unittests/table_json_conversion/test_table_template_generator.py @@ -69,7 +69,7 @@ def test_generate_sheets_from_schema(): with pytest.raises(ValueError, match="Inappropriate JSON schema: The following part " "should define an object.*"): - generator._generate_sheets_from_schema(schema) + generator._generate_sheets_from_schema(schema, {'Training': ['a']}) # bad schema schema = { @@ -83,7 +83,7 @@ def test_generate_sheets_from_schema(): with pytest.raises(ValueError, match="Inappropriate JSON schema: The following part " "should define an object.*"): - generator._generate_sheets_from_schema(schema) + generator._generate_sheets_from_schema(schema, {'Training': ['a']}) # minimal case: one RT with one P schema = { @@ -100,7 +100,7 @@ def test_generate_sheets_from_schema(): } } } - sdef = generator._generate_sheets_from_schema(schema) + sdef = generator._generate_sheets_from_schema(schema, {'Training': ['a']}) assert "Training" in sdef tdef = sdef['Training'] assert 'name' in tdef @@ -111,8 +111,9 @@ def test_generate_sheets_from_schema(): schema = json.load(sfi) with pytest.raises(ValueError, match="A foreign key definition is missing.*"): generator._generate_sheets_from_schema(schema) - sdef = generator._generate_sheets_from_schema(schema, - foreign_keys={'Training': {"__this__": ['date', 'url']}}) + sdef = generator._generate_sheets_from_schema( + schema, + foreign_keys={'Training': {"__this__": ['date', 'url']}}) assert "Training" in sdef tdef = sdef['Training'] assert tdef['date'] == (ColumnType.SCALAR, 'date', ["Training", 'date']) @@ -127,7 +128,7 @@ def test_generate_sheets_from_schema(): assert tdef['participants'] == (ColumnType.SCALAR, None, ["Training", 'participants']) assert tdef['subjects'] == (ColumnType.LIST, None, ["Training", 'subjects']) assert tdef['remote'] == (ColumnType.SCALAR, None, ["Training", 'remote']) - cdef = sdef['coach'] + cdef = sdef['Training.coach'] assert cdef['family_name'] == (ColumnType.SCALAR, None, ["Training", 'coach', 'family_name']) assert cdef['given_name'] == (ColumnType.SCALAR, None, ["Training", 'coach', 'given_name']) assert cdef['Organisation'] == (ColumnType.SCALAR, None, ["Training", 'coach', @@ -166,7 +167,9 @@ def test_template_generator(): schema = json.load(sfi) path = os.path.join(tempfile.mkdtemp(), 'test.xlsx') assert not os.path.exists(path) - generator.generate(schema=schema, foreign_keys={'Training': {"__this__": ['date', 'url']}}, filepath=path) + generator.generate(schema=schema, + foreign_keys={'Training': {"__this__": ['date', 'url']}}, + filepath=path) assert os.path.exists(path) generated = load_workbook(path) # workbook can be read example = load_workbook(rfp("example_template.xlsx")) @@ -195,9 +198,7 @@ def test_template_generator(): continue with open(fk_path) as sfi: fk = json.load(sfi) - generator.generate(schema=schema, - foreign_keys=fk, - filepath=path) + generator.generate(schema=schema, foreign_keys=fk, filepath=path) os.system(f'libreoffice {path}') # TODO test collisions of sheet or colnames