Skip to content

Commit 281461e

Browse files
committed
[validation] Use validation_id in handlers
1 parent e0dc454 commit 281461e

File tree

1 file changed

+64
-30
lines changed

1 file changed

+64
-30
lines changed

odml/validation.py

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

213215
Validation.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

228232
Validation.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

256262
def 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

324334
Validation.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

387404
Validation.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

410429
Validation.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

437458
Validation.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

469491
Validation.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

522546
Validation.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

Comments
 (0)