@@ -36,7 +36,8 @@ def get_logger():
36
36
stream_handler = logging .StreamHandler (stream = sys .stdout )
37
37
stream_handler .setFormatter (ColorFormatter ('%(message)s' ))
38
38
logger .addHandler (stream_handler )
39
- logger .setLevel (logging .WARNING )
39
+ logger .setLevel (logging .WARNING )
40
+ logger .total = {'warning' : 0 , 'error' : 0 }
40
41
return logger
41
42
42
43
@@ -346,6 +347,58 @@ def get_valid_attributes(self):
346
347
self .valid_attributes = valid_attributes
347
348
self .partial_attributes = partial_attributes
348
349
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
+
349
402
def reset_symbols (self ):
350
403
"""
351
404
Resets all symbols dictionaries to be empty.
@@ -356,7 +409,7 @@ def reset_symbols(self):
356
409
for symbol in self .symbols :
357
410
self .symbols [symbol ] = {}
358
411
359
- def check_symbols (self ):
412
+ def check_symbols (self , indent = None ):
360
413
"""
361
414
Checks for inconsistent values in the symbols dictionary.
362
415
@@ -365,6 +418,8 @@ def check_symbols(self):
365
418
'info' level. If two values differ by more than 1, prints a
366
419
message at the 'error' level.
367
420
"""
421
+ if indent is not None :
422
+ self .indent = indent
368
423
for symbol in self .symbols :
369
424
values = []
370
425
for entry in self .symbols [symbol ]:
@@ -469,35 +524,7 @@ def validate(self, group, indent=0):
469
524
f'"@{ attribute } " is not defined as an attribute'
470
525
f' in { group .nxclass } ' , level = 'warning' )
471
526
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 )
501
528
502
529
self .reset_symbols ()
503
530
for entry in group .entries :
@@ -633,7 +660,11 @@ def check_dimensions(self, field, dimensions):
633
660
f'but the dimension index of "{ s } " = { i } ' ,
634
661
level = 'error' )
635
662
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 :
637
668
self .log (f'The field has the correct size of { s } ' )
638
669
else :
639
670
self .log (f'The field has size { field .shape } , '
@@ -897,6 +928,10 @@ def validate_file(filename, path=None, definitions=None):
897
928
898
929
validator .validate (path )
899
930
931
+ log (f'\n Total number of errors: { logger .total ["error" ]} ' , level = 'all' )
932
+ log (f'Total number of warnings: { logger .total ["warning" ]} \n ' , level = 'all' )
933
+
934
+
900
935
901
936
class ApplicationValidator (Validator ):
902
937
@@ -910,6 +945,7 @@ def __init__(self, application, definitions=None):
910
945
The name of the application to be validated.
911
946
"""
912
947
super ().__init__ (definitions = definitions )
948
+ self .symbols = {}
913
949
self .xml_dict = self .load_application (application )
914
950
915
951
def load_application (self , application ):
@@ -948,6 +984,9 @@ def load_application(self, application):
948
984
raise NeXusError (
949
985
f'The application definition { application } '
950
986
'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' ])
951
990
xml_dict = xml_to_dict (xml_root .find ('group' ))
952
991
if xml_root .attrib ['extends' ] != 'NXobject' :
953
992
xml_extended_dict = self .load_application (
@@ -976,6 +1015,8 @@ def validate_group(self, xml_dict, nxgroup, level=0):
976
1015
The current indentation level (default is 0).
977
1016
"""
978
1017
self .indent = level
1018
+ group_validator = get_validator (nxgroup .nxclass ,
1019
+ definitions = self .definitions )
979
1020
for key , value in xml_dict .items ():
980
1021
if key == 'group' :
981
1022
for group in value :
@@ -1016,8 +1057,7 @@ def validate_group(self, xml_dict, nxgroup, level=0):
1016
1057
else :
1017
1058
minOccurs = 1
1018
1059
if field in nxgroup .entries :
1019
- group_validator = get_validator (
1020
- nxgroup .nxclass , definitions = self .definitions )
1060
+ group_validator .symbols .update (self .symbols )
1021
1061
field_validator .validate (
1022
1062
value [field ], nxgroup [field ],
1023
1063
parent = group_validator , minOccurs = minOccurs ,
@@ -1037,7 +1077,9 @@ def validate_group(self, xml_dict, nxgroup, level=0):
1037
1077
'in the NeXus file' )
1038
1078
self .indent -= 1
1039
1079
self .output_log ()
1040
-
1080
+ group_validator .check_symbols (indent = level )
1081
+ self .output_log ()
1082
+
1041
1083
def validate (self , entry ):
1042
1084
"""
1043
1085
Validates a NeXus entry against an XML definition.
@@ -1097,6 +1139,10 @@ def validate_application(filename, path=None, application=None,
1097
1139
1098
1140
validator .validate (entry )
1099
1141
1142
+ log (f'\n Total number of errors: { logger .total ["error" ]} ' , level = 'all' )
1143
+ log (f'Total number of warnings: { logger .total ["warning" ]} \n ' ,
1144
+ level = 'all' )
1145
+
1100
1146
1101
1147
def inspect_base_class (base_class , definitions = None ):
1102
1148
"""
@@ -1185,7 +1231,9 @@ def log(message, level='info', indent=0, width=None):
1185
1231
logger .log (logging .DEBUG , f'{ 4 * indent * " " } { message } ' )
1186
1232
elif level == 'warning' :
1187
1233
logger .warning (f'{ 4 * indent * " " } { message } ' )
1234
+ logger .total ['warning' ] += 1
1188
1235
elif level == 'error' :
1189
1236
logger .error (f'{ 4 * indent * " " } { message } ' )
1237
+ logger .total ['error' ] += 1
1190
1238
elif level == 'all' :
1191
1239
logger .critical (f'{ 4 * indent * " " } { message } ' )
0 commit comments