Skip to content

Commit d9d5223

Browse files
authored
Merge pull request #372 from fschrader1992/validation
Validation Name and Property Tuple Extend
2 parents 91c963d + 1d8e055 commit d9d5223

File tree

5 files changed

+103
-52
lines changed

5 files changed

+103
-52
lines changed

odml/property.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,8 @@ def extend(self, obj, strict=True):
688688
dtypes.infer_dtype(new_value[0]) != self.dtype:
689689

690690
type_check = dtypes.infer_dtype(new_value[0])
691-
if not (type_check == "string" and self.dtype in dtypes.special_dtypes):
691+
if not (type_check == "string" and self.dtype in dtypes.special_dtypes) \
692+
and not self.dtype.endswith("-tuple"):
692693
msg = "odml.Property.extend: passed value data type found "
693694
msg += "(\"%s\") does not match expected dtype \"%s\"!" % (type_check,
694695
self._dtype)
@@ -724,7 +725,8 @@ def append(self, obj, strict=True):
724725
dtypes.infer_dtype(new_value[0]) != self.dtype:
725726

726727
type_check = dtypes.infer_dtype(new_value[0])
727-
if not (type_check == "string" and self.dtype in dtypes.special_dtypes):
728+
if not (type_check == "string" and self.dtype in dtypes.special_dtypes) \
729+
and not self.dtype.endswith("-tuple"):
728730
msg = "odml.Property.append: passed value data type found "
729731
msg += "(\"%s\") does not match expected dtype \"%s\"!" % (type_check,
730732
self._dtype)

odml/validation.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def object_required_attributes(obj):
134134
for arg in args:
135135
if arg[1] == 1:
136136
if not hasattr(obj, arg[0]):
137-
msg = "Missing attribute %s for %s" % (obj.format().name.capitalize(), arg[0])
137+
msg = "Missing attribute %s for %s" % (arg[0], obj.format().name.capitalize())
138138
yield ValidationError(obj, msg, LABEL_ERROR)
139139
continue
140140
obj_arg = getattr(obj, arg[0])
@@ -308,6 +308,20 @@ def property_unique_names(obj):
308308
Validation.register_handler('section', property_unique_names)
309309

310310

311+
def object_name_readable(obj):
312+
"""
313+
Tests if object name is easily readable, so not equal to id.
314+
315+
:param obj: odml.Section or odml.Property.
316+
"""
317+
if obj.name == obj.id:
318+
yield ValidationError(obj, 'Name should be readable', LABEL_WARNING)
319+
320+
321+
Validation.register_handler('section', object_name_readable)
322+
Validation.register_handler('property', object_name_readable)
323+
324+
311325
def property_terminology_check(prop):
312326
"""
313327
1. warn, if there are properties that do not occur in the terminology.

test/test_fileio.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class TestTypes(unittest.TestCase):
1313
# TODO :- Write tests for JSONParser once it's completed.
1414

1515
def setUp(self):
16-
self.file = 'doc/example_odMLs/THGTTG.odml'
16+
self.dir_path = os.path.dirname(os.path.realpath(__file__))
17+
self.file = os.path.join(self.dir_path, 'resources', 'example.odml')
1718
# Do not allow anything to be printed on STDOUT
1819
self.captured_stdout = StringIO()
1920
sys.stdout = self.captured_stdout

test/test_property.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ def test_value_append(self):
231231
self.assertRaises(ValueError, p8.append, 1.3)
232232
self.assertRaises(ValueError, p8.append, True)
233233

234+
prop = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)")
235+
prop.append("(7; 8; 9)")
236+
self.assertEqual(len(prop), 2)
237+
self.assertRaises(ValueError, prop.append, "(10; 11)")
238+
234239
def test_value_extend(self):
235240
prop = Property(name="extend")
236241

@@ -274,7 +279,7 @@ def test_value_extend(self):
274279
prop.extend(ext_prop)
275280
self.assertEqual(prop.values, ["a", "b", "c", "d", "e"])
276281

277-
ext_prop = Property(name="value extend", value=[1, 2 ,3])
282+
ext_prop = Property(name="value extend", value=[1, 2, 3])
278283
with self.assertRaises(ValueError):
279284
prop.extend(ext_prop)
280285
self.assertEqual(prop.values, ["a", "b", "c", "d", "e"])
@@ -318,16 +323,21 @@ def test_value_extend(self):
318323
p2 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"], dtype=DType.url)
319324
p2.extend("https://en.wikipedia.org/wiki/Mars")
320325
self.assertEqual(len(p2), 2)
321-
self.assertRaises(ValueError, p2.append, 1)
322-
self.assertRaises(ValueError, p2.append, 1.3)
323-
self.assertRaises(ValueError, p2.append, True)
326+
self.assertRaises(ValueError, p2.extend, 1)
327+
self.assertRaises(ValueError, p2.extend, 1.3)
328+
self.assertRaises(ValueError, p2.extend, True)
324329

325330
p3 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text)
326331
p3.extend("Mars is No. 4.")
327332
self.assertEqual(len(p3), 2)
328-
self.assertRaises(ValueError, p3.append, 1)
329-
self.assertRaises(ValueError, p3.append, 1.3)
330-
self.assertRaises(ValueError, p3.append, True)
333+
self.assertRaises(ValueError, p3.extend, 1)
334+
self.assertRaises(ValueError, p3.extend, 1.3)
335+
self.assertRaises(ValueError, p3.extend, True)
336+
337+
prop = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)")
338+
prop.extend(["(7; 8; 9)", "(10; 11; 12)"])
339+
self.assertEqual(len(prop), 3)
340+
self.assertRaises(ValueError, prop.extend, "(10; 11)")
331341

332342
def test_get_set_value(self):
333343
values = [1, 2, 3, 4, 5]
@@ -736,12 +746,12 @@ def test_comparison(self):
736746
p_val = ["a", "b"]
737747

738748
prop_a = Property(name=p_name, value_origin=p_origin, unit=p_unit,
739-
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
740-
dependency=p_dep, dependency_value=p_dep_val, value=p_val)
749+
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
750+
dependency=p_dep, dependency_value=p_dep_val, value=p_val)
741751

742752
prop_b = Property(name=p_name, value_origin=p_origin, unit=p_unit,
743-
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
744-
dependency=p_dep, dependency_value=p_dep_val, value=p_val)
753+
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
754+
dependency=p_dep, dependency_value=p_dep_val, value=p_val)
745755

746756
self.assertEqual(prop_a, prop_b)
747757

test/test_validation.py

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import unittest
22
import odml
33
import os
4+
import sys
45
import odml.validation
56
import odml.terminology
67
from . import test_samplefile as samplefile
78

9+
try:
10+
from StringIO import StringIO
11+
except ImportError:
12+
from io import StringIO
13+
814
validate = odml.validation.Validation
915

1016

@@ -129,6 +135,27 @@ def test_section_unique_ids(self):
129135
res = validate(doc)
130136
self.assertError(res, "Duplicate id in Section")
131137

138+
def test_section_name_readable(self):
139+
"""
140+
Test if section name is not uuid and thus more readable.
141+
"""
142+
doc = odml.Document()
143+
sec = odml.Section("sec", parent=doc)
144+
sec.name = sec.id
145+
res = validate(doc)
146+
self.assertError(res, "Name should be readable")
147+
148+
def test_property_name_readable(self):
149+
"""
150+
Test if property name is not uuid and thus more readable.
151+
"""
152+
doc = odml.Document()
153+
sec = odml.Section("sec", parent=doc)
154+
prop = odml.Property("prop", parent=sec)
155+
prop.name = prop.id
156+
res = validate(doc)
157+
self.assertError(res, "Name should be readable")
158+
132159
def test_standalone_section(self):
133160
"""
134161
Test if standalone section does not return errors if required attributes are correct.
@@ -152,8 +179,20 @@ def test_standalone_property(self):
152179
prop = odml.Property()
153180
prop.type = ""
154181

155-
for err in validate(prop).errors:
156-
assert not err.is_error
182+
assert len(list(filter(lambda x: x.is_error, validate(prop).errors))) == 0
183+
184+
def test_section_init(self):
185+
"""
186+
Test validation errors printed to stdout on section init.
187+
"""
188+
val_errs = StringIO()
189+
190+
old_stdout = sys.stdout
191+
sys.stdout = val_errs
192+
odml.Section(name="sec", type=None)
193+
sys.stdout = old_stdout
194+
195+
assert "Section type undefined" in val_errs.getvalue()
157196

158197
def test_prop_string_values(self):
159198
"""
@@ -172,8 +211,8 @@ def test_prop_string_values(self):
172211

173212
prop2 = odml.Property(name='potential', dtype="string",
174213
values=['-4.8', '10.0', '-11.9', '-10.0', '18.0'])
175-
self.assertError(validate(prop2),'Dtype of property "potential" currently is "string", '
176-
'but might fit dtype "float"!')
214+
self.assertError(validate(prop2), 'Dtype of property "potential" currently is "string", '
215+
'but might fit dtype "float"!')
177216

178217
prop3 = odml.Property(name='dates', dtype="string",
179218
values=['1997-12-14', '00-12-14', '89-07-04'])
@@ -219,17 +258,12 @@ def test_load_section_xml(self):
219258
path = os.path.join(self.dir_path, "resources", "validation_section.xml")
220259
doc = odml.load(path)
221260

222-
sec_type_undefined_err = False
223-
sec_type_empty_err = False
224-
225-
for err in validate(doc).errors:
226-
if err.msg == "Section type undefined" and err.obj.name == "sec_type_undefined":
227-
sec_type_undefined_err = True
228-
elif err.msg == "Section type undefined" and err.obj.name == "sec_type_empty":
229-
sec_type_empty_err = True
230-
231-
assert sec_type_undefined_err
232-
assert sec_type_empty_err
261+
assert len(list(filter(
262+
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_undefined",
263+
validate(doc).errors))) > 0
264+
assert len(list(filter(
265+
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_empty",
266+
validate(doc).errors))) > 0
233267

234268
def test_load_dtypes_xml(self):
235269
"""
@@ -298,17 +332,12 @@ def test_load_section_json(self):
298332
path = os.path.join(self.dir_path, "resources", "validation_section.json")
299333
doc = odml.load(path, "JSON")
300334

301-
sec_type_undefined_err = False
302-
sec_type_empty_err = False
303-
304-
for err in validate(doc).errors:
305-
if err.msg == "Section type undefined" and err.obj.name == "sec_type_undefined":
306-
sec_type_undefined_err = True
307-
elif err.msg == "Section type undefined" and err.obj.name == "sec_type_empty":
308-
sec_type_empty_err = True
309-
310-
assert sec_type_undefined_err
311-
assert sec_type_empty_err
335+
assert len(list(filter(
336+
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_undefined",
337+
validate(doc).errors))) > 0
338+
assert len(list(filter(
339+
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_empty",
340+
validate(doc).errors))) > 0
312341

313342
def test_load_dtypes_json(self):
314343
"""
@@ -377,17 +406,12 @@ def test_load_section_yaml(self):
377406
path = os.path.join(self.dir_path, "resources", "validation_section.yaml")
378407
doc = odml.load(path, "YAML")
379408

380-
sec_type_undefined_err = False
381-
sec_type_empty_err = False
382-
383-
for err in validate(doc).errors:
384-
if err.msg == "Section type undefined" and err.obj.name == "sec_type_undefined":
385-
sec_type_undefined_err = True
386-
elif err.msg == "Section type undefined" and err.obj.name == "sec_type_empty":
387-
sec_type_empty_err = True
388-
389-
assert sec_type_undefined_err
390-
assert sec_type_empty_err
409+
assert len(list(filter(
410+
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_undefined",
411+
validate(doc).errors))) > 0
412+
assert len(list(filter(
413+
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_empty",
414+
validate(doc).errors))) > 0
391415

392416
def test_load_dtypes_yaml(self):
393417
"""

0 commit comments

Comments
 (0)