Skip to content

Commit dc22feb

Browse files
authored
Merge pull request #31 from rayosborn:check_axes
Check_axes
2 parents bceee9f + 4030b4b commit dc22feb

File tree

1 file changed

+83
-35
lines changed

1 file changed

+83
-35
lines changed

src/nxvalidate/validate.py

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ def get_logger():
3636
stream_handler = logging.StreamHandler(stream=sys.stdout)
3737
stream_handler.setFormatter(ColorFormatter('%(message)s'))
3838
logger.addHandler(stream_handler)
39-
logger.setLevel(logging.WARNING)
39+
logger.setLevel(logging.WARNING)
40+
logger.total = {'warning': 0, 'error': 0}
4041
return logger
4142

4243

@@ -346,6 +347,58 @@ def get_valid_attributes(self):
346347
self.valid_attributes = valid_attributes
347348
self.partial_attributes = partial_attributes
348349

350+
def check_data(self, group):
351+
"""
352+
Checks that the signal and axes are present in the group.
353+
354+
This method also checks that the axes have the correct length
355+
and that the axis sizes match the signal shape.
356+
357+
Parameters
358+
----------
359+
group : NXgroup
360+
The group to be checked.
361+
"""
362+
if 'signal' in group.attrs:
363+
signal = group.attrs['signal']
364+
if signal in group.entries:
365+
self.log(f'Signal "{signal}" is present in the group',
366+
level='info')
367+
signal_field = group[signal]
368+
else:
369+
self.log(f'Signal "{signal}" is not present in the group',
370+
level='error')
371+
signal = None
372+
else:
373+
self.log(f'"@signal" is not present in the group', level='error')
374+
signal = None
375+
if 'axes' in group.attrs:
376+
axes = readaxes(group.attrs['axes'])
377+
if signal in group and group[signal].exists():
378+
if len(axes) != group[signal].ndim:
379+
self.log('"@axes" length does not match the signal rank',
380+
level='error')
381+
else:
382+
self.log('"@axes" has the correct length')
383+
for i, axis in enumerate(axes):
384+
if axis in group.entries:
385+
self.log(f'Axis "{axis}" is present in the group',
386+
level='info')
387+
axis_field = group[axis]
388+
if signal in group and group[signal].exists():
389+
if check_dimension_sizes(
390+
[signal_field.shape[i], axis_field.shape[0]]):
391+
self.log(f'Axis "{axis}" size is consistent '
392+
'with the signal shape', level='info')
393+
else:
394+
self.log(f'Axis "{axis}" size is inconsistent '
395+
'with the signal shape', level='error')
396+
elif axis != '.':
397+
self.log(f'Axis "{axis}" is not present in the group',
398+
level='error')
399+
else:
400+
self.log(f'"@axes" is not present in the group', level='error')
401+
349402
def reset_symbols(self):
350403
"""
351404
Resets all symbols dictionaries to be empty.
@@ -356,7 +409,7 @@ def reset_symbols(self):
356409
for symbol in self.symbols:
357410
self.symbols[symbol] = {}
358411

359-
def check_symbols(self):
412+
def check_symbols(self, indent=None):
360413
"""
361414
Checks for inconsistent values in the symbols dictionary.
362415
@@ -365,6 +418,8 @@ def check_symbols(self):
365418
'info' level. If two values differ by more than 1, prints a
366419
message at the 'error' level.
367420
"""
421+
if indent is not None:
422+
self.indent = indent
368423
for symbol in self.symbols:
369424
values = []
370425
for entry in self.symbols[symbol]:
@@ -469,35 +524,7 @@ def validate(self, group, indent=0):
469524
f'"@{attribute}" is not defined as an attribute'
470525
f' in {group.nxclass}', level='warning')
471526
if group.nxclass == 'NXdata':
472-
if 'signal' in group.attrs:
473-
signal = group.attrs['signal']
474-
if signal not in group.entries:
475-
self.log(
476-
f'Signal "{signal}" is not present in the group'
477-
f' "{group.nxpath}"', level='error')
478-
else:
479-
signal = None
480-
self.log(
481-
f'"@signal" is not present in the group "{group.nxpath}"',
482-
level='error')
483-
if 'axes' in group.attrs:
484-
axes = readaxes(group.attrs['axes'])
485-
for axis in axes:
486-
if axis != '.' and axis not in group.entries:
487-
self.log(
488-
f'Axis {axis}" is not present in the group '
489-
f'"{group.nxpath}"', level='error')
490-
if signal in group and group[signal].exists():
491-
if len(axes) != group[signal].ndim:
492-
self.log(
493-
'"@axes" length does not match the signal rank',
494-
level='error')
495-
else:
496-
self.log('"@axes" has the correct length')
497-
else:
498-
self.log(
499-
f'"@axes" is not present in the group "{group.nxpath}"',
500-
level='error')
527+
self.check_data(group)
501528

502529
self.reset_symbols()
503530
for entry in group.entries:
@@ -633,7 +660,11 @@ def check_dimensions(self, field, dimensions):
633660
f'but the dimension index of "{s}" = {i}',
634661
level='error')
635662
else:
636-
if len(field.shape) > i and field.shape[i-1] == int(s):
663+
try:
664+
s = int(s)
665+
except ValueError:
666+
pass
667+
if len(field.shape) > i and field.shape[i-1] == s:
637668
self.log(f'The field has the correct size of {s}')
638669
else:
639670
self.log(f'The field has size {field.shape}, '
@@ -897,6 +928,10 @@ def validate_file(filename, path=None, definitions=None):
897928

898929
validator.validate(path)
899930

931+
log(f'\nTotal number of errors: {logger.total["error"]}', level='all')
932+
log(f'Total number of warnings: {logger.total["warning"]}\n', level='all')
933+
934+
900935

901936
class ApplicationValidator(Validator):
902937

@@ -910,6 +945,7 @@ def __init__(self, application, definitions=None):
910945
The name of the application to be validated.
911946
"""
912947
super().__init__(definitions=definitions)
948+
self.symbols = {}
913949
self.xml_dict = self.load_application(application)
914950

915951
def load_application(self, application):
@@ -948,6 +984,9 @@ def load_application(self, application):
948984
raise NeXusError(
949985
f'The application definition {application}'
950986
'does not contain the correct root tag.')
987+
symbols = xml_root.find('symbols')
988+
if symbols is not None:
989+
self.symbols.update(xml_to_dict(symbols)['symbol'])
951990
xml_dict = xml_to_dict(xml_root.find('group'))
952991
if xml_root.attrib['extends'] != 'NXobject':
953992
xml_extended_dict = self.load_application(
@@ -976,6 +1015,8 @@ def validate_group(self, xml_dict, nxgroup, level=0):
9761015
The current indentation level (default is 0).
9771016
"""
9781017
self.indent = level
1018+
group_validator = get_validator(nxgroup.nxclass,
1019+
definitions=self.definitions)
9791020
for key, value in xml_dict.items():
9801021
if key == 'group':
9811022
for group in value:
@@ -1016,8 +1057,7 @@ def validate_group(self, xml_dict, nxgroup, level=0):
10161057
else:
10171058
minOccurs = 1
10181059
if field in nxgroup.entries:
1019-
group_validator = get_validator(
1020-
nxgroup.nxclass, definitions=self.definitions)
1060+
group_validator.symbols.update(self.symbols)
10211061
field_validator.validate(
10221062
value[field], nxgroup[field],
10231063
parent=group_validator, minOccurs=minOccurs,
@@ -1037,7 +1077,9 @@ def validate_group(self, xml_dict, nxgroup, level=0):
10371077
'in the NeXus file')
10381078
self.indent -= 1
10391079
self.output_log()
1040-
1080+
group_validator.check_symbols(indent=level)
1081+
self.output_log()
1082+
10411083
def validate(self, entry):
10421084
"""
10431085
Validates a NeXus entry against an XML definition.
@@ -1097,6 +1139,10 @@ def validate_application(filename, path=None, application=None,
10971139

10981140
validator.validate(entry)
10991141

1142+
log(f'\nTotal number of errors: {logger.total["error"]}', level='all')
1143+
log(f'Total number of warnings: {logger.total["warning"]}\n',
1144+
level='all')
1145+
11001146

11011147
def inspect_base_class(base_class, definitions=None):
11021148
"""
@@ -1185,7 +1231,9 @@ def log(message, level='info', indent=0, width=None):
11851231
logger.log(logging.DEBUG, f'{4*indent*" "}{message}')
11861232
elif level == 'warning':
11871233
logger.warning(f'{4*indent*" "}{message}')
1234+
logger.total['warning'] += 1
11881235
elif level == 'error':
11891236
logger.error(f'{4*indent*" "}{message}')
1237+
logger.total['error'] += 1
11901238
elif level == 'all':
11911239
logger.critical(f'{4*indent*" "}{message}')

0 commit comments

Comments
 (0)