-
Notifications
You must be signed in to change notification settings - Fork 13
Error for multiple different variadic concepts with the same name #646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
2e27912
eaba076
29f290e
d499cc6
0225333
40295fa
8d0e62b
aacf70e
6daffdc
14f9562
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -850,6 +850,94 @@ def recurse_tree( | |
|
|
||
| handling_map.get(child.type, handle_unknown_type)(child, keys, prev_path) | ||
|
|
||
| def find_instance_name_conflicts( | ||
| mapping: MutableMapping[str, str], keys_to_remove: List[str] | ||
| ) -> None: | ||
| """ | ||
| Detect and log conflicts where the same variadic instance name is reused across | ||
| different concept names. | ||
|
|
||
| This function ensures that a given instance name (e.g., 'my_name') is only used | ||
| for a single concept (e.g., SAMPLE or USER, but not both). Reusing the same instance | ||
| name for different concept names (e.g., SAMPLE[my_name] and USER[my_name]) is | ||
| considered a conflict. | ||
|
|
||
| For example, this is a conflict: | ||
| /ENTRY[entry1]/SAMPLE[my_name]/... | ||
| /ENTRY[entry1]/USER[my_name]/... | ||
|
|
||
| But this is NOT a conflict: | ||
| /ENTRY[entry1]/INSTRUMENT[instrument]/FIELD[my_name]/... | ||
| /ENTRY[entry1]/INSTRUMENT[instrument]/DETECTOR[detector]/FIELD[my_name]/... | ||
|
|
||
| When such conflicts are found, an error is logged indicating the instance name | ||
| and the conflicting concept names. Additionally, all keys involved in the conflict | ||
| are logged and added to the `keys_to_remove` list. | ||
|
|
||
| Args: | ||
| mapping (MutableMapping[str, str]): | ||
| The mapping containing the data to validate. | ||
| This should be a dict of `/` separated paths, such as | ||
| "/ENTRY[entry1]/SAMPLE[sample1]/name". | ||
| keys_to_remove (List[str]): | ||
| List of keys that will be removed from the template. This is extended here | ||
| in the case of conflicts. | ||
|
|
||
| """ | ||
| pattern = re.compile(r"(?P<concept_name>[^\[\]/]+)\[(?P<instance>[^\]]+)\]") | ||
|
|
||
| # Tracks instance usage with respect to their parent group | ||
| instance_usage: Dict[Tuple[str, str], List[Tuple[str, str]]] = defaultdict(list) | ||
|
|
||
| for key in mapping: | ||
| matches = list(pattern.finditer(key)) | ||
| if not matches: | ||
| # The keys contains no concepts with variable name, no need to further check | ||
| continue | ||
| for match in matches: | ||
| concept_name = match.group("concept_name") | ||
| instance_name = match.group("instance") | ||
|
|
||
| # Determine the parent path up to just before this match | ||
| parent_path = key[: match.start()] | ||
| instance_usage[(instance_name, parent_path)].append((concept_name, key)) | ||
|
|
||
| for (instance_name, parent_path), entries in sorted(instance_usage.items()): | ||
| concept_names = {c for c, _ in entries} | ||
| if len(concept_names) > 1: | ||
| keys = sorted(k for _, k in entries) | ||
| collector.collect_and_log( | ||
| instance_name, | ||
| ValidationProblem.DifferentVariadicNodesWithTheSameName, | ||
| entries, | ||
| ) | ||
| # Now that we have name conflicts, we still need to check that there are | ||
| # at least two valid keys in that conclit. Only then we remove these. | ||
|
lukaspie marked this conversation as resolved.
Outdated
|
||
| # This takes care of the example with keys like | ||
| # /ENTRY[my_entry]/USER[some_name]/name and /ENTRY[my_entry]/USERS[some_name]/name, | ||
| # where we only want to keep the first one. | ||
| valid_keys_with_name_conflicts = [] | ||
|
|
||
| for key in keys: | ||
| try: | ||
| node = add_best_matches_for(key, tree) | ||
| if node is not None: | ||
| valid_keys_with_name_conflicts.append(key) | ||
| continue | ||
| except TypeError: | ||
| pass | ||
|
Comment on lines
+949
to
+950
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When do we arrive here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| collector.collect_and_log( | ||
| key, ValidationProblem.KeyToBeRemoved, "key" | ||
| ) | ||
| keys_to_remove.append(key) | ||
|
|
||
| if len(valid_keys_with_name_conflicts) > 1: | ||
| for valid_key in valid_keys_with_name_conflicts: | ||
| collector.collect_and_log( | ||
| valid_key, ValidationProblem.KeyToBeRemoved, "key" | ||
| ) | ||
| keys_to_remove.append(valid_key) | ||
|
|
||
| def check_attributes_of_nonexisting_field( | ||
| node: NexusNode, | ||
| ): | ||
|
|
@@ -1174,10 +1262,11 @@ def check_reserved_prefix( | |
| "choice": handle_choice, | ||
| } | ||
|
|
||
| keys_to_remove = [] | ||
| keys_to_remove: List[str] = [] | ||
|
|
||
| tree = generate_tree_from(appdef) | ||
| collector.clear() | ||
| find_instance_name_conflicts(mapping, keys_to_remove) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the functions below, you don't pass the keys_to_remove, but use them from the global context. Why is this handled differently here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had the function somewhere else first, where the global context was not available. Removed it now. |
||
| nested_keys = build_nested_dict_from(mapping) | ||
| not_visited = list(mapping) | ||
| keys = _follow_link(nested_keys, "") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.