Skip to content

Commit f626a83

Browse files
committed
check for target attribute in template link
1 parent da46189 commit f626a83

File tree

3 files changed

+55
-21
lines changed

3 files changed

+55
-21
lines changed

src/pynxtools/dataconverter/helpers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,12 @@ def _log(self, path: str, log_type: ValidationProblem, value: Optional[Any], *ar
171171
elif log_type == ValidationProblem.BrokenLink:
172172
logger.warning(f"Broken link at {path} to {value}.")
173173
elif log_type == ValidationProblem.MissingTargetAttribute:
174-
logger.info(
174+
log_text = (
175175
f"A link was used for {path}, but no '@target' attribute was found."
176176
)
177+
if value is not None:
178+
log_text += f" The link target was automatically set to {value}."
179+
logger.info(log_text)
177180
elif log_type == ValidationProblem.TargetAttributeMismatch:
178181
logger.info(
179182
f"A link was used for {path}, but its @target attribute '{value}' "
@@ -252,6 +255,8 @@ def collect_and_log(
252255
if log_type in (
253256
ValidationProblem.UnitWithoutDocumentation,
254257
ValidationProblem.OpenEnumWithNewItem,
258+
ValidationProblem.MissingTargetAttribute,
259+
ValidationProblem.TargetAttributeMismatch,
255260
ValidationProblem.CompressionStrengthZero,
256261
):
257262
if self.logging and message not in self.data["info"]:

src/pynxtools/dataconverter/validation.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ def visititems(group: h5py.Group, path: str = "", filename: str = ""):
872872

873873
if "target" not in group[name].attrs:
874874
collector.collect_and_log(
875-
full_path, ValidationProblem.MissingTargetAttribute, ""
875+
full_path, ValidationProblem.MissingTargetAttribute, None
876876
)
877877
else:
878878
attr_target = group[name].attrs["target"]
@@ -1229,7 +1229,7 @@ def remove_from_not_visited(path: str) -> str:
12291229
return path
12301230

12311231
def _follow_link(
1232-
keys: Optional[Mapping[str, Any]], prev_path: str, p=False
1232+
keys: Optional[Mapping[str, Any]], prev_path: str
12331233
) -> Optional[Any]:
12341234
"""
12351235
Resolves internal dictionary "links" by replacing any keys containing a
@@ -1284,9 +1284,30 @@ def _follow_link(
12841284
"key",
12851285
)
12861286
keys_to_remove.append(key_path)
1287+
keys_to_remove.append(f"{key_path}/@target")
12871288
del resolved_keys[key]
12881289
else:
12891290
resolved_keys[key] = current_keys
1291+
1292+
if f"{key_path}/@target" not in mapping:
1293+
collector.collect_and_log(
1294+
key_path,
1295+
ValidationProblem.MissingTargetAttribute,
1296+
value["link"],
1297+
)
1298+
mapping[f"{key_path}/@target"] = value["link"]
1299+
else:
1300+
attr_target = mapping[f"{key_path}/@target"]
1301+
remove_from_not_visited(f"{key_path}/@target")
1302+
target_path = value["link"]
1303+
if attr_target != target_path:
1304+
collector.collect_and_log(
1305+
key_path,
1306+
ValidationProblem.TargetAttributeMismatch,
1307+
attr_target,
1308+
target_path,
1309+
)
1310+
12901311
return resolved_keys
12911312

12921313
def handle_field(node: NexusNode, keys: Mapping[str, Any], prev_path: str):
@@ -2135,18 +2156,13 @@ def check_reserved_prefix(
21352156
keys = _follow_link(nested_keys, "")
21362157
recurse_tree(tree, nested_keys)
21372158

2138-
check_attributes_of_nonexisting_field(tree)
2159+
# check_attributes_of_nonexisting_field(tree)
21392160

21402161
for not_visited_key in not_visited:
21412162
if mapping.get(not_visited_key) is None:
21422163
# This value is not really set. Skip checking its validity.
21432164
continue
21442165

2145-
# TODO: remove again if "@target"/"@reference" is sorted out by NIAC
2146-
always_allowed_attributes = ("@target", "@reference")
2147-
if not_visited_key.endswith(always_allowed_attributes):
2148-
# If we want to support this in the future, we could check that the targetted field exists.
2149-
continue
21502166
if not_visited_key.endswith("/@units"):
21512167
# check that parent exists
21522168
if not_visited_key.rsplit("/", 1)[0] not in mapping.keys():
@@ -2247,7 +2263,8 @@ def check_reserved_prefix(
22472263

22482264
# remove keys that are incorrect
22492265
for key in set(keys_to_remove):
2250-
del mapping[key]
2266+
if key in mapping:
2267+
del mapping[key]
22512268

22522269
return not collector.has_validation_problems()
22532270

tests/dataconverter/test_validation.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -991,16 +991,24 @@ def format_error_message(msg: str) -> str:
991991
pytest.param(
992992
alter_dict(
993993
alter_dict(
994-
remove_from_dict(
995-
TEMPLATE,
996-
"/ENTRY[my_entry]/required_group/description",
997-
"optional",
994+
alter_dict(
995+
alter_dict(
996+
remove_from_dict(
997+
TEMPLATE,
998+
"/ENTRY[my_entry]/required_group/description",
999+
"optional",
1000+
),
1001+
"/ENTRY[my_entry]/required_group",
1002+
{"link": "/my_entry/required_group2"},
1003+
),
1004+
"/ENTRY[my_entry]/required_group/@target",
1005+
"/my_entry/required_group2",
9981006
),
999-
"/ENTRY[my_entry]/required_group",
1000-
{"link": "/my_entry/required_group2"},
1007+
"/ENTRY[my_entry]/OPTIONAL_group[some_group]/required_field",
1008+
{"link": "/my_entry/specified_group/specified_field"},
10011009
),
1002-
"/ENTRY[my_entry]/OPTIONAL_group[some_group]/required_field",
1003-
{"link": "/my_entry/specified_group/specified_field"},
1010+
"/ENTRY[my_entry]/OPTIONAL_group[some_group]/required_field/@target",
1011+
"/my_entry/specified_group/specified_field",
10041012
),
10051013
[],
10061014
id="appdef-links-with-matching-nexus-types",
@@ -1025,9 +1033,13 @@ def format_error_message(msg: str) -> str:
10251033
pytest.param(
10261034
alter_dict(
10271035
alter_dict(
1028-
TEMPLATE,
1029-
"/ENTRY[my_entry]/SAMPLE[my_sample]",
1030-
{"link": "/my_entry/some_group"},
1036+
alter_dict(
1037+
TEMPLATE,
1038+
"/ENTRY[my_entry]/SAMPLE[my_sample]",
1039+
{"link": "/my_entry/some_group"},
1040+
),
1041+
"/ENTRY[my_entry]/SAMPLE[my_sample]/@target",
1042+
"/my_entry/some_group",
10311043
),
10321044
"/ENTRY[my_entry]/SAMPLE[my_sample2]/name",
10331045
{"link": "/my_entry/specified_group/some_field223"},

0 commit comments

Comments
 (0)