Skip to content

Commit 6daffdc

Browse files
committed
catch case where there are multiple fields in the conflicting groups
1 parent aacf70e commit 6daffdc

File tree

2 files changed

+116
-39
lines changed

2 files changed

+116
-39
lines changed

src/pynxtools/dataconverter/validation.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -929,12 +929,23 @@ def find_instance_name_conflicts(mapping: MutableMapping[str, str]) -> None:
929929
)
930930
keys_to_remove.append(key)
931931

932-
if len(valid_keys_with_name_conflicts) > 1:
933-
for valid_key in valid_keys_with_name_conflicts:
934-
collector.collect_and_log(
935-
valid_key, ValidationProblem.KeyToBeRemoved, "key"
936-
)
937-
keys_to_remove.append(valid_key)
932+
if len(valid_keys_with_name_conflicts) >= 1:
933+
# At this point, all invalid keys have been removed.
934+
# If more than one valid concept still uses the same instance name under the same parent path,
935+
# this indicates a semantic ambiguity (e.g., USER[alex] and SAMPLE[alex]).
936+
# We remove these keys as well to avoid conflicts in the writer.
937+
remaining_concepts = {
938+
pattern.findall(k)[-1][0]
939+
for k in valid_keys_with_name_conflicts
940+
if pattern.findall(k)
941+
}
942+
# If multiple valid concept names reuse the same instance name, remove them too
943+
if len(remaining_concepts) > 1:
944+
for valid_key in valid_keys_with_name_conflicts:
945+
collector.collect_and_log(
946+
valid_key, ValidationProblem.KeyToBeRemoved, "key"
947+
)
948+
keys_to_remove.append(valid_key)
938949

939950
def check_attributes_of_nonexisting_field(
940951
node: NexusNode,

tests/dataconverter/test_validation.py

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -240,53 +240,119 @@ def listify_template(data_dict: Template):
240240
alter_dict(
241241
alter_dict(
242242
alter_dict(
243-
alter_dict(
244-
alter_dict(
245-
alter_dict(
246-
TEMPLATE,
247-
"/ENTRY[my_entry]/SAMPLE[some_name]/name",
248-
"A sample name",
249-
),
250-
"/ENTRY[my_entry]/USER[some_name]/name",
251-
"A user name",
252-
),
253-
"/ENTRY[my_entry]/MONITOR[some_name]/name",
254-
"An monitor name",
255-
),
256-
"/ENTRY[my_entry]/INSTRUMENT[instrument]/APERTURE[another_name]/name",
257-
"An aperture within an instrument",
243+
TEMPLATE,
244+
"/ENTRY[my_entry]/SAMPLE[some_name]/name",
245+
"A sample name",
258246
),
259-
"/ENTRY[my_entry]/INSTRUMENT[instrument]/DETECTOR[another_name]/name",
260-
"A detector within an instrument",
247+
"/ENTRY[my_entry]/SAMPLE[some_name]/description",
248+
"A sample description",
261249
),
262-
"/ENTRY[my_entry]/INSTRUMENT[instrument]/SOURCE[my_source]/APERTURE[another_name]/name",
263-
"An aperture within a source inside an instrument",
250+
"/ENTRY[my_entry]/USER[some_name]/name",
251+
"A user name",
264252
),
265-
"/ENTRY[my_entry]/USER[a_third_name]/name",
266-
"A tird user name",
253+
"/ENTRY[my_entry]/MONITOR[some_name]/name",
254+
"A monitor name",
267255
),
268-
"/ENTRY[my_entry]/USERS[a_third_name]/name",
269-
"An invalid group of the same name",
256+
"/ENTRY[my_entry]/MONITOR[some_name]/description",
257+
"A monitor description",
270258
),
271259
[
272-
"Instance name 'a_third_name' used for multiple different concepts: USER, USERS. "
273-
"The following keys are affected: /ENTRY[my_entry]/USERS[a_third_name]/name, "
274-
"/ENTRY[my_entry]/USER[a_third_name]/name.",
275-
"The key /ENTRY[my_entry]/USERS[a_third_name]/name will not be written.",
276-
"Instance name 'another_name' used for multiple different concepts: APERTURE, DETECTOR. "
277-
"The following keys are affected: /ENTRY[my_entry]/INSTRUMENT[instrument]/APERTURE[another_name]/name, "
278-
"/ENTRY[my_entry]/INSTRUMENT[instrument]/DETECTOR[another_name]/name.",
279-
"The key /ENTRY[my_entry]/INSTRUMENT[instrument]/APERTURE[another_name]/name will not be written.",
280-
"The key /ENTRY[my_entry]/INSTRUMENT[instrument]/DETECTOR[another_name]/name will not be written.",
281260
"Instance name 'some_name' used for multiple different concepts: MONITOR, SAMPLE, USER. "
282-
"The following keys are affected: /ENTRY[my_entry]/MONITOR[some_name]/name, "
261+
"The following keys are affected: /ENTRY[my_entry]/MONITOR[some_name]/description, "
262+
"/ENTRY[my_entry]/MONITOR[some_name]/name, /ENTRY[my_entry]/SAMPLE[some_name]/description, "
283263
"/ENTRY[my_entry]/SAMPLE[some_name]/name, /ENTRY[my_entry]/USER[some_name]/name.",
264+
"The key /ENTRY[my_entry]/MONITOR[some_name]/description will not be written.",
284265
"The key /ENTRY[my_entry]/MONITOR[some_name]/name will not be written.",
266+
"The key /ENTRY[my_entry]/SAMPLE[some_name]/description will not be written.",
285267
"The key /ENTRY[my_entry]/SAMPLE[some_name]/name will not be written.",
286268
"The key /ENTRY[my_entry]/USER[some_name]/name will not be written.",
287269
],
288270
id="variadic-groups-of-the-same-name",
289271
),
272+
pytest.param(
273+
alter_dict(
274+
alter_dict(
275+
alter_dict(
276+
TEMPLATE,
277+
"/ENTRY[my_entry]/INSTRUMENT[instrument]/APERTURE[another_name]/name",
278+
"An aperture within an instrument",
279+
),
280+
"/ENTRY[my_entry]/INSTRUMENT[instrument]/DETECTOR[another_name]/name",
281+
"A detector within an instrument",
282+
),
283+
"/ENTRY[my_entry]/INSTRUMENT[instrument]/SOURCE[my_source]/APERTURE[another_name]/name",
284+
"An aperture within a source inside an instrument",
285+
),
286+
[
287+
"Instance name 'another_name' used for multiple different concepts: APERTURE, DETECTOR. "
288+
"The following keys are affected: /ENTRY[my_entry]/INSTRUMENT[instrument]/APERTURE[another_name]/name, "
289+
"/ENTRY[my_entry]/INSTRUMENT[instrument]/DETECTOR[another_name]/name.",
290+
"The key /ENTRY[my_entry]/INSTRUMENT[instrument]/APERTURE[another_name]/name will not be written.",
291+
"The key /ENTRY[my_entry]/INSTRUMENT[instrument]/DETECTOR[another_name]/name will not be written.",
292+
],
293+
id="variadic-groups-of-the-same-name-but-at-different-levels",
294+
),
295+
pytest.param(
296+
alter_dict(
297+
alter_dict(
298+
alter_dict(
299+
alter_dict(
300+
alter_dict(
301+
alter_dict(
302+
TEMPLATE,
303+
"/ENTRY[my_entry]/USER[user]/name",
304+
"A user name",
305+
),
306+
"/ENTRY[my_entry]/USER[user]/role",
307+
"A user role",
308+
),
309+
"/ENTRY[my_entry]/USER[user]/affiliation",
310+
"A user affiliation",
311+
),
312+
"/ENTRY[my_entry]/ILLEGAL[user]/name",
313+
"An illegal user name",
314+
),
315+
"/ENTRY[my_entry]/ILLEGAL[user]/role",
316+
"An illegal user role",
317+
),
318+
"/ENTRY[my_entry]/ILLEGAL[user]/affiliation",
319+
"An illegal user affiliation",
320+
),
321+
[
322+
"Instance name 'user' used for multiple different concepts: ILLEGAL, USER. "
323+
"The following keys are affected: /ENTRY[my_entry]/ILLEGAL[user]/affiliation, /ENTRY[my_entry]/ILLEGAL[user]/name, "
324+
"/ENTRY[my_entry]/ILLEGAL[user]/role, /ENTRY[my_entry]/USER[user]/affiliation, /ENTRY[my_entry]/USER[user]/name, "
325+
"/ENTRY[my_entry]/USER[user]/role.",
326+
"The key /ENTRY[my_entry]/ILLEGAL[user]/affiliation will not be written.",
327+
"The key /ENTRY[my_entry]/ILLEGAL[user]/name will not be written.",
328+
"The key /ENTRY[my_entry]/ILLEGAL[user]/role will not be written.",
329+
],
330+
id="variadic-groups-of-the-same-name-illegal-concept-multiple-fields",
331+
),
332+
pytest.param(
333+
alter_dict(
334+
alter_dict(
335+
alter_dict(
336+
TEMPLATE,
337+
"/ENTRY[my_entry]/USER[user]/name",
338+
"A user name",
339+
),
340+
"/ENTRY[my_entry]/USERS[user]/name",
341+
"An invalid group of the same name",
342+
),
343+
"/ENTRY[my_entry]/SAMPLE[user]/name",
344+
"A sample group called user with a name",
345+
),
346+
[
347+
"Instance name 'user' used for multiple different concepts: SAMPLE, USER, USERS. "
348+
"The following keys are affected: /ENTRY[my_entry]/SAMPLE[user]/name, "
349+
"/ENTRY[my_entry]/USERS[user]/name, /ENTRY[my_entry]/USER[user]/name.",
350+
"The key /ENTRY[my_entry]/USERS[user]/name will not be written.",
351+
"The key /ENTRY[my_entry]/SAMPLE[user]/name will not be written.",
352+
"The key /ENTRY[my_entry]/USER[user]/name will not be written.",
353+
],
354+
id="variadic-groups-of-the-same-name-mix-of-valid-and-illegal-concepts",
355+
),
290356
pytest.param(
291357
alter_dict(
292358
alter_dict(

0 commit comments

Comments
 (0)