@@ -55,10 +55,11 @@ class ValidationError(object):
5555 a message and a rank which may be one of: 'error', 'warning'.
5656 """
5757
58- def __init__ (self , obj , msg , rank = LABEL_ERROR ):
58+ def __init__ (self , obj , msg , rank = LABEL_ERROR , validation_id = None ):
5959 self .obj = obj
6060 self .msg = msg
6161 self .rank = rank
62+ self .validation_id = validation_id
6263
6364 @property
6465 def is_warning (self ):
@@ -197,17 +198,18 @@ def object_required_attributes(obj):
197198
198199 :param obj: document, section or property.
199200 """
201+ validation_id = ValidationID .object_required_attributes
200202
201203 args = obj .format ().arguments
202204 for arg in args :
203205 if arg [1 ] == 1 :
204206 msg = "Missing required attribute '%s'" % (arg [0 ])
205207 if not hasattr (obj , arg [0 ]):
206- yield ValidationError (obj , msg , LABEL_ERROR )
208+ yield ValidationError (obj , msg , LABEL_ERROR , validation_id )
207209 continue
208210 obj_arg = getattr (obj , arg [0 ])
209211 if not obj_arg and not isinstance (obj_arg , bool ):
210- yield ValidationError (obj , msg , LABEL_ERROR )
212+ yield ValidationError (obj , msg , LABEL_ERROR , validation_id )
211213
212214
213215Validation .register_handler ('odML' , object_required_attributes )
@@ -221,8 +223,10 @@ def section_type_must_be_defined(sec):
221223
222224 :param sec: odml.Section.
223225 """
226+ validation_id = ValidationID .section_type_must_be_defined
227+
224228 if sec .type and sec .type == "n.s." :
225- yield ValidationError (sec , "Section type not specified" , LABEL_WARNING )
229+ yield ValidationError (sec , "Section type not specified" , LABEL_WARNING , validation_id )
226230
227231
228232Validation .register_handler ('section' , section_type_must_be_defined )
@@ -235,22 +239,24 @@ def section_repository_present(sec):
235239 1. warn, if a section has no repository or
236240 2. the section type is not present in the repository
237241 """
242+ validation_id = ValidationID .section_repository_present
243+
238244 repo = sec .get_repository ()
239245 if repo is None :
240246 msg = "A section should have an associated repository"
241- yield ValidationError (sec , msg , LABEL_WARNING )
247+ yield ValidationError (sec , msg , LABEL_WARNING , validation_id )
242248 return
243249
244250 try :
245251 tsec = sec .get_terminology_equivalent ()
246252 except Exception as exc :
247253 msg = "Could not load terminology: %s" % exc
248- yield ValidationError (sec , msg , LABEL_WARNING )
254+ yield ValidationError (sec , msg , LABEL_WARNING , validation_id )
249255 return
250256
251257 if tsec is None :
252258 msg = "Section type '%s' not found in terminology" % sec .type
253- yield ValidationError (sec , msg , LABEL_WARNING )
259+ yield ValidationError (sec , msg , LABEL_WARNING , validation_id )
254260
255261
256262def document_unique_ids (doc ):
@@ -280,6 +286,8 @@ def section_unique_ids(parent, id_map=None):
280286 :param parent: odML Document or Section
281287 :param id_map: "id":"odML object / path" dictionary
282288 """
289+ validation_id = ValidationID .section_unique_ids
290+
283291 if not id_map :
284292 id_map = {}
285293
@@ -289,7 +297,7 @@ def section_unique_ids(parent, id_map=None):
289297
290298 if sec .id in id_map :
291299 msg = "Duplicate id in Section '%s' and %s" % (sec .get_path (), id_map [sec .id ])
292- yield ValidationError (sec , msg )
300+ yield ValidationError (sec , msg , validation_id = validation_id )
293301 else :
294302 id_map [sec .id ] = "Section '%s'" % sec .get_path ()
295303
@@ -309,39 +317,43 @@ def property_unique_ids(section, id_map=None):
309317 :param section: odML Section
310318 :param id_map: "id":"odML object / path" dictionary
311319 """
320+ validation_id = ValidationID .property_unique_ids
321+
312322 if not id_map :
313323 id_map = {}
314324
315325 for prop in section .properties :
316326 if prop .id in id_map :
317327 msg = "Duplicate id in Property '%s' and %s" % (prop .get_path (),
318328 id_map [prop .id ])
319- yield ValidationError (prop , msg )
329+ yield ValidationError (prop , msg , validation_id = validation_id )
320330 else :
321331 id_map [prop .id ] = "Property '%s'" % prop .get_path ()
322332
323333
324334Validation .register_handler ('odML' , document_unique_ids )
325335
326336
327- def object_unique_names (obj , children , attr = lambda x : x .name ,
337+ def object_unique_names (obj , validation_id , children , attr = lambda x : x .name ,
328338 msg = "Object names must be unique" ):
329339 """
330- Tests that object names within one Section are unique.
340+ Tests that object names within a Section are unique.
331341
332342 :param obj: odml class instance the validation is applied on.
343+ :param validation_id: id of the
333344 :param children: a function that returns the children to be considered.
334- This is to be able to use the same function for sections and properties .
335- :param attr: a function that returns the item that needs to be unique
336- :param msg: error message that will be registered upon a ValidationError.
345+ Required when handling Sections .
346+ :param attr: a function that returns the attribute that needs to be unique.
347+ :param msg: error message that will be registered with a ValidationError.
337348 """
338349 names = set (map (attr , children (obj )))
339350 if len (names ) == len (children (obj )):
340- return # quick exit
351+ return
352+
341353 names = set ()
342354 for i in children (obj ):
343355 if attr (i ) in names :
344- yield ValidationError (i , msg , LABEL_ERROR )
356+ yield ValidationError (i , msg , LABEL_ERROR , validation_id )
345357 names .add (attr (i ))
346358
347359
@@ -353,6 +365,7 @@ def section_unique_name_type(obj):
353365 """
354366 for i in object_unique_names (
355367 obj ,
368+ validation_id = ValidationID .section_unique_name_type ,
356369 attr = lambda x : (x .name , x .type ),
357370 children = lambda x : x .sections ,
358371 msg = "name/type combination must be unique" ):
@@ -365,7 +378,9 @@ def property_unique_names(obj):
365378
366379 :param obj: odml class instance the validation is applied on.
367380 """
368- for i in object_unique_names (obj , lambda x : x .properties ):
381+ for i in object_unique_names (obj ,
382+ validation_id = ValidationID .property_unique_name ,
383+ children = lambda x : x .properties ):
369384 yield i
370385
371386
@@ -380,8 +395,10 @@ def object_name_readable(obj):
380395
381396 :param obj: odml.Section or odml.Property.
382397 """
398+ validation_id = ValidationID .object_name_readable
399+
383400 if obj .name == obj .id :
384- yield ValidationError (obj , ' Name should be readable' , LABEL_WARNING )
401+ yield ValidationError (obj , " Name should be readable" , LABEL_WARNING , validation_id )
385402
386403
387404Validation .register_handler ('section' , object_name_readable )
@@ -394,6 +411,8 @@ def property_terminology_check(prop):
394411 2. warn, if there are multiple values with different units or the unit does
395412 not match the one in the terminology.
396413 """
414+ validation_id = ValidationID .property_terminology_check
415+
397416 if not prop .parent :
398417 return
399418
@@ -404,7 +423,7 @@ def property_terminology_check(prop):
404423 tsec .properties [prop .name ]
405424 except KeyError :
406425 msg = "Property '%s' not found in terminology" % prop .name
407- yield ValidationError (prop , msg , LABEL_WARNING )
426+ yield ValidationError (prop , msg , LABEL_WARNING , validation_id )
408427
409428
410429Validation .register_handler ('property' , property_terminology_check )
@@ -415,6 +434,8 @@ def property_dependency_check(prop):
415434 Produces a warning if the dependency attribute refers to a non-existent attribute
416435 or the dependency_value does not match.
417436 """
437+ validation_id = ValidationID .property_dependency_check
438+
418439 if not prop .parent :
419440 return
420441
@@ -426,12 +447,12 @@ def property_dependency_check(prop):
426447 dep_obj = prop .parent [dep ]
427448 except KeyError :
428449 msg = "Property refers to a non-existent dependency object"
429- yield ValidationError (prop , msg , LABEL_WARNING )
450+ yield ValidationError (prop , msg , LABEL_WARNING , validation_id )
430451 return
431452
432453 if prop .dependency_value not in dep_obj .values [0 ]:
433454 msg = "Dependency-value is not equal to value of the property's dependency"
434- yield ValidationError (prop , msg , LABEL_WARNING )
455+ yield ValidationError (prop , msg , LABEL_WARNING , validation_id )
435456
436457
437458Validation .register_handler ('property' , property_dependency_check )
@@ -444,6 +465,7 @@ def property_values_check(prop):
444465
445466 :param prop: property the validation is applied on.
446467 """
468+ validation_id = ValidationID .property_values_check
447469
448470 if prop .dtype is not None and prop .dtype != "" :
449471 dtype = prop .dtype
@@ -457,13 +479,13 @@ def property_values_check(prop):
457479 tuple_len = int (dtype [:- 6 ])
458480 if len (val ) != tuple_len :
459481 msg = "Tuple of length %s not consistent with dtype %s!" % (len (val ), dtype )
460- yield ValidationError (prop , msg , LABEL_WARNING )
482+ yield ValidationError (prop , msg , LABEL_WARNING , validation_id )
461483 else :
462484 try :
463485 dtypes .get (val , dtype )
464486 except ValueError :
465487 msg = "Property values not of consistent dtype!"
466- yield ValidationError (prop , msg , LABEL_WARNING )
488+ yield ValidationError (prop , msg , LABEL_WARNING , validation_id )
467489
468490
469491Validation .register_handler ('property' , property_values_check )
@@ -477,6 +499,7 @@ def property_values_string_check(prop):
477499
478500 :param prop: property the validation is applied on.
479501 """
502+ validation_id = ValidationID .property_values_string_check
480503
481504 if prop .dtype != "string" or not prop .values :
482505 return
@@ -515,14 +538,15 @@ def property_values_string_check(prop):
515538 res_dtype = "string"
516539
517540 if res_dtype != "string" :
518- msg = 'Dtype of property "%s" currently is "string", but might fit dtype "%s"!' % (prop .name , res_dtype )
519- yield ValidationError (prop , msg , LABEL_WARNING )
541+ msg = 'Dtype of property "%s" currently is "string", but might fit dtype "%s"!' % \
542+ (prop .name , res_dtype )
543+ yield ValidationError (prop , msg , LABEL_WARNING , validation_id )
520544
521545
522546Validation .register_handler ('property' , property_values_string_check )
523547
524548
525- def _cardinality_validation (obj , cardinality , card_target_attr , validation_rank ):
549+ def _cardinality_validation (obj , cardinality , card_target_attr , validation_rank , validation_id ):
526550 """
527551 Helper function that validates the cardinality of an odml object attribute.
528552 Valid object-attribute combinations are Section-sections, Section-properties and
@@ -534,6 +558,7 @@ def _cardinality_validation(obj, cardinality, card_target_attr, validation_rank)
534558 applied against. Supported values are:
535559 'sections', 'properties' or 'values'
536560 :param validation_rank: Rank of the yielded ValidationError.
561+ :param validation_id: string containing the id of the parent validation.
537562
538563 :return: Returns a ValidationError, if a set cardinality is not met or None.
539564 """
@@ -557,7 +582,7 @@ def _cardinality_validation(obj, cardinality, card_target_attr, validation_rank)
557582 msg = "%s %s cardinality violated" % (obj_name , card_target_attr )
558583 msg += " (%s values, %s found)" % (invalid_cause , val_len )
559584
560- err = ValidationError (obj , msg , validation_rank )
585+ err = ValidationError (obj , msg , validation_rank , validation_id )
561586
562587 return err
563588
@@ -570,7 +595,10 @@ def section_properties_cardinality(obj):
570595
571596 :return: Yields a ValidationError warning, if a set cardinality is not met.
572597 """
573- err = _cardinality_validation (obj , obj .prop_cardinality , 'properties' , LABEL_WARNING )
598+ validation_id = ValidationID .section_properties_cardinality
599+
600+ err = _cardinality_validation (obj , obj .prop_cardinality , 'properties' ,
601+ LABEL_WARNING , validation_id )
574602 if err :
575603 yield err
576604
@@ -586,7 +614,10 @@ def section_sections_cardinality(obj):
586614
587615 :return: Yields a ValidationError warning, if a set cardinality is not met.
588616 """
589- err = _cardinality_validation (obj , obj .sec_cardinality , 'sections' , LABEL_WARNING )
617+ validation_id = ValidationID .section_sections_cardinality
618+
619+ err = _cardinality_validation (obj , obj .sec_cardinality , 'sections' ,
620+ LABEL_WARNING , validation_id )
590621 if err :
591622 yield err
592623
@@ -602,7 +633,10 @@ def property_values_cardinality(obj):
602633
603634 :return: Yields a ValidationError warning, if a set cardinality is not met.
604635 """
605- err = _cardinality_validation (obj , obj .val_cardinality , 'values' , LABEL_WARNING )
636+ validation_id = ValidationID .property_values_cardinality
637+
638+ err = _cardinality_validation (obj , obj .val_cardinality , 'values' ,
639+ LABEL_WARNING , validation_id )
606640 if err :
607641 yield err
608642
0 commit comments