-
Notifications
You must be signed in to change notification settings - Fork 12
Undescriptive error message for undefined group #623
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 all commits
ff1506e
d9218ff
3ed3e57
15d7217
b4166c5
315664e
26bbd0c
f53a43f
b94e99d
4ede930
907cf01
40dbe2f
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 |
|---|---|---|
|
|
@@ -21,7 +21,6 @@ | |
|
|
||
| import copy | ||
| import logging | ||
| import sys | ||
| import xml.etree.ElementTree as ET | ||
|
|
||
| import h5py | ||
|
|
@@ -117,7 +116,9 @@ def handle_dicts_entries(data, grp, entry_name, output_path, path): | |
| - Concatenate dataset in one virtual dataset | ||
| - Internal links | ||
| - External links | ||
| - compression label""" | ||
| - compression label | ||
| """ | ||
| file = None | ||
| if "link" in data: | ||
| file, path = split_link(data, output_path) | ||
| # generate virtual datasets from slices | ||
|
|
@@ -246,11 +247,19 @@ def ensure_and_get_parent_node(self, path: str, undocumented_paths) -> h5py.Grou | |
| if not does_path_exist(parent_path, self.output_nexus): | ||
| parent = self.ensure_and_get_parent_node(parent_path, undocumented_paths) | ||
| grp = parent.create_group(parent_path_hdf5) | ||
|
|
||
| attrs = self.__nxdl_to_attrs(parent_path) | ||
| if attrs is not None and (nx_class := attrs.get("type", "")): | ||
| grp.attrs["NX_class"] = nx_class | ||
| else: | ||
| logger.warning( | ||
| "NXDL attribute `type` not found for group %s.\n" | ||
| "Hint: Follow the convention `fixednameVARIADICPART[fixedname_given_name]` " | ||
| "or `non_variadic_group` where `fixednameVARIADICPART` is a variadic name " | ||
| "and `non_variadic_group` is a fixed name of the group defined in NXDL file " | ||
| "Or no such group exists in NXDL file.", | ||
| parent_path, | ||
| ) | ||
|
|
||
| if attrs is not None: | ||
| grp.attrs["NX_class"] = attrs["type"] | ||
| return grp | ||
| return self.output_nexus[parent_path_hdf5] | ||
|
|
||
|
|
@@ -259,82 +268,73 @@ def _put_data_into_hdf5(self): | |
|
|
||
| hdf5_links_for_later = [] | ||
|
|
||
| def add_units_key(dataset, path): | ||
| units_key = f"{path}/@units" | ||
| if units_key in self.data.keys() and self.data[units_key] is not None: | ||
| dataset.attrs["units"] = self.data[units_key] | ||
| unit_and_attr = {} | ||
|
|
||
| for path, value in self.data.items(): | ||
| for path, d_value in self.data.items(): | ||
| if not is_not_data_empty(d_value): | ||
| continue | ||
| try: | ||
| if path[path.rindex("/") + 1 :] == "@units": | ||
| continue | ||
|
|
||
| entry_name = helpers.get_name_from_data_dict_entry( | ||
| path[path.rindex("/") + 1 :] | ||
| ) | ||
| if is_not_data_empty(value): | ||
| data = value | ||
| else: | ||
| if entry_name and entry_name.startswith("@"): | ||
| unit_and_attr[path] = d_value | ||
| continue | ||
|
|
||
| if entry_name[0] != "@": | ||
| grp = self.ensure_and_get_parent_node( | ||
| path, self.data.undocumented.keys() | ||
| ) | ||
| if isinstance(data, dict): | ||
| if "compress" in data.keys(): | ||
| dataset = handle_dicts_entries( | ||
| data, grp, entry_name, self.output_path, path | ||
| ) | ||
| else: | ||
| hdf5_links_for_later.append( | ||
| [data, grp, entry_name, self.output_path, path] | ||
| ) | ||
| # Handle fields and groups | ||
| grp = self.ensure_and_get_parent_node( | ||
| path, | ||
| self.data.undocumented.keys(), | ||
| ) | ||
| if isinstance(d_value, dict): | ||
| if "compress" in d_value.keys(): | ||
| dataset = handle_dicts_entries( | ||
| d_value, grp, entry_name, self.output_path, path | ||
| ) | ||
| else: | ||
| dataset = grp.create_dataset(entry_name, data=data) | ||
| hdf5_links_for_later.append( | ||
| [d_value, grp, entry_name, self.output_path, path] | ||
| ) | ||
| else: | ||
| dataset = grp.create_dataset(entry_name, data=d_value) | ||
|
|
||
| except InvalidDictProvided as exc: | ||
| print(str(exc)) | ||
| except Exception as exc: | ||
| raise IOError( | ||
| f"Unknown error occured writing the path: {path} " | ||
| f"with the following message: {str(exc)}" | ||
| f"with the following message: {str(exc)}\n" | ||
| ) from exc | ||
|
|
||
| # Handle links | ||
| for links in hdf5_links_for_later: | ||
| dataset = handle_dicts_entries(*links) | ||
| if dataset is None: | ||
| # If target of a link is invalid to be linked | ||
| del self.data[links[-1]] | ||
|
|
||
| for path, value in self.data.items(): | ||
| # Handle units and attributes | ||
| for path, d_value in unit_and_attr.items(): | ||
| hdf5_path = helpers.convert_data_dict_path_to_hdf5_path(path) | ||
| entry_name = helpers.get_name_from_data_dict_entry( | ||
| path[path.rindex("/") + 1 :] | ||
| ) | ||
| try: | ||
| if path[path.rindex("/") + 1 :] == "@units": | ||
| continue | ||
|
|
||
| entry_name = helpers.get_name_from_data_dict_entry( | ||
| path[path.rindex("/") + 1 :] | ||
| dataset_or_grp = self.ensure_and_get_parent_node( | ||
| path, | ||
| self.data.undocumented.keys(), | ||
| ) | ||
| if is_not_data_empty(value): | ||
| data = value | ||
| else: | ||
| continue | ||
|
|
||
| if entry_name[0] != "@": | ||
| path_hdf5 = helpers.convert_data_dict_path_to_hdf5_path(path) | ||
|
|
||
| add_units_key(self.output_nexus[path_hdf5], path) | ||
| else: | ||
| # consider changing the name here the lvalue can also be group! | ||
| dataset = self.ensure_and_get_parent_node( | ||
| path, self.data.undocumented.keys() | ||
| ) | ||
| dataset.attrs[entry_name[1:]] = data | ||
| except Exception as exc: | ||
| raise IOError( | ||
| f"Unknown error occured writing the path: {path}" | ||
| f", while writing the value: {value} " | ||
| f"with the following message: {str(exc)}" | ||
| ) from exc | ||
| except KeyError as exc: | ||
| logger.warning( | ||
| "No path '%s' available to attached Attribute.", hdf5_path | ||
| ) | ||
| dataset_or_grp = None | ||
| if dataset_or_grp is None: | ||
| continue | ||
| if path.endswith("/@units"): | ||
| dataset_or_grp.attrs["units"] = d_value | ||
| else: | ||
| dataset_or_grp.attrs[entry_name[1:]] = d_value | ||
|
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. What issue do these changes solve? I don't understand it.
Contributor
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. It does not solve anything. This separates the concept handling of
Collaborator
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. Why do they need to be separated? What do we gain from this? If we have so many changes to the code, it would be good to understand the reasoning for why these changes are made. |
||
|
|
||
| def write(self): | ||
| """Writes the NeXus file with previously validated data from the reader with NXDL attrs.""" | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't think that error message makes that much sense. The first case (i.e., not using
fixednameVARIADICPART[fixedname_given_name]for a concept that has a renameable part) is now fixed by #621, so I don't think we will get to this point if you don't use it properly. Thus, that part of the error message can be removed. I think if you rebase on top of master, such a problem will not occur here anymore.The actual issue is if we try to attach a field for a group that doesn't exist, but for which the same name is used as a field. For example, using
"/ENTRY/entry_identifier/identifier"as a key.entry_identifieris a field with XML attributedeprecatedinNXentry, but with this notation we are using it as if it were a named group. Obviously, a field cannot have a sub-field itself, so that will lead to problems. We should instead raise an error that we are trying to write a group with a name that is reserved for a field instead.This is something that should be caught by the validation instead of in the writer IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not allow giving a group some name that is defined as the name of an field/attribute on the same level in general. This may be technically allowed in NeXus, but will break the whole NOMAD integration (since groups are (sub)sections and fields are quantities).
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we can remove the error massage 👍, as this message mainly says the
invalidgroup ormisdefinedgroup. This sort of wanrinig is part of the validation. Here, writer will write the nexus file, if anything is wrong with the writing process that should be handeled here. To check a group, a field or attribute has proper annotation is not part of the writer.However, in a point I am a bit confused that is raising error wrting a group with the same name of
attributeorfield(which may come from mistyping, or just a regular error). In that case,groupwould not get propernx_classname in such case NOMAD just will overlook that group in registering. Because, nomad can not match that group with any of the subsection in nomad metainfo.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this creates the whole problem in the first place. We could consider to allow it to pass, but raise a strong and descriptive warning message.
With the current master, this still gets through validation with
WARNING: Field /ENTRY[entry]/entry_identifier/identifier written without documentation.And no hint to the conflicting concept, and then breaks in the writer.
I would suggest to do three things:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current master, you can actually provide something like:
And it breaks writing, but in a different fashion:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WARNING: Given field name 'COLLECTION' conflicts with the non-variadic name 'entry_identifier (opt)'This is already correctly throwing a warning (should be an error though), but it should probably tell you that one is a field (defined and deprcated in `NXentry´) and the other is a new group.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I can create two PRs referring to this PR.
I think both of the warnings are properly described the issue here.
E.g., the warning
WARNING: Field /ENTRY[entry]/entry_identifier/identifier written without documentationsays the correct warning. Indeed, there is not such groupentry_identifierand even no such field.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not allow this in the first place if there is also a field called
entry_identifierdefined at the same level.