Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions odml/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,8 @@ def extend(self, obj, strict=True):
dtypes.infer_dtype(new_value[0]) != self.dtype:

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

type_check = dtypes.infer_dtype(new_value[0])
if not (type_check == "string" and self.dtype in dtypes.special_dtypes):
if not (type_check == "string" and self.dtype in dtypes.special_dtypes) \
and not self.dtype.endswith("-tuple"):
msg = "odml.Property.append: passed value data type found "
msg += "(\"%s\") does not match expected dtype \"%s\"!" % (type_check,
self._dtype)
Expand Down
16 changes: 15 additions & 1 deletion odml/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def object_required_attributes(obj):
for arg in args:
if arg[1] == 1:
if not hasattr(obj, arg[0]):
msg = "Missing attribute %s for %s" % (obj.format().name.capitalize(), arg[0])
msg = "Missing attribute %s for %s" % (arg[0], obj.format().name.capitalize())
yield ValidationError(obj, msg, LABEL_ERROR)
continue
obj_arg = getattr(obj, arg[0])
Expand Down Expand Up @@ -308,6 +308,20 @@ def property_unique_names(obj):
Validation.register_handler('section', property_unique_names)


def object_name_readable(obj):
"""
Tests if object name is easily readable, so not equal to id.

:param obj: odml.Section or odml.Property.
"""
if obj.name == obj.id:
yield ValidationError(obj, 'Name should be readable', LABEL_WARNING)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the message to "Name should be human readable" to make it clearer whats expected of the user; but we can change this at a later point in time.



Validation.register_handler('section', object_name_readable)
Validation.register_handler('property', object_name_readable)


def property_terminology_check(prop):
"""
1. warn, if there are properties that do not occur in the terminology.
Expand Down
3 changes: 2 additions & 1 deletion test/test_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class TestTypes(unittest.TestCase):
# TODO :- Write tests for JSONParser once it's completed.

def setUp(self):
self.file = 'doc/example_odMLs/THGTTG.odml'
self.dir_path = os.path.dirname(os.path.realpath(__file__))
self.file = os.path.join(self.dir_path, 'resources', 'example.odml')
# Do not allow anything to be printed on STDOUT
self.captured_stdout = StringIO()
sys.stdout = self.captured_stdout
Expand Down
32 changes: 21 additions & 11 deletions test/test_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ def test_value_append(self):
self.assertRaises(ValueError, p8.append, 1.3)
self.assertRaises(ValueError, p8.append, True)

prop = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)")
prop.append("(7; 8; 9)")
self.assertEqual(len(prop), 2)
self.assertRaises(ValueError, prop.append, "(10; 11)")

def test_value_extend(self):
prop = Property(name="extend")

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

ext_prop = Property(name="value extend", value=[1, 2 ,3])
ext_prop = Property(name="value extend", value=[1, 2, 3])
with self.assertRaises(ValueError):
prop.extend(ext_prop)
self.assertEqual(prop.values, ["a", "b", "c", "d", "e"])
Expand Down Expand Up @@ -318,16 +323,21 @@ def test_value_extend(self):
p2 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"], dtype=DType.url)
p2.extend("https://en.wikipedia.org/wiki/Mars")
self.assertEqual(len(p2), 2)
self.assertRaises(ValueError, p2.append, 1)
self.assertRaises(ValueError, p2.append, 1.3)
self.assertRaises(ValueError, p2.append, True)
self.assertRaises(ValueError, p2.extend, 1)
self.assertRaises(ValueError, p2.extend, 1.3)
self.assertRaises(ValueError, p2.extend, True)

p3 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text)
p3.extend("Mars is No. 4.")
self.assertEqual(len(p3), 2)
self.assertRaises(ValueError, p3.append, 1)
self.assertRaises(ValueError, p3.append, 1.3)
self.assertRaises(ValueError, p3.append, True)
self.assertRaises(ValueError, p3.extend, 1)
self.assertRaises(ValueError, p3.extend, 1.3)
self.assertRaises(ValueError, p3.extend, True)

prop = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)")
prop.extend(["(7; 8; 9)", "(10; 11; 12)"])
self.assertEqual(len(prop), 3)
self.assertRaises(ValueError, prop.extend, "(10; 11)")

def test_get_set_value(self):
values = [1, 2, 3, 4, 5]
Expand Down Expand Up @@ -736,12 +746,12 @@ def test_comparison(self):
p_val = ["a", "b"]

prop_a = Property(name=p_name, value_origin=p_origin, unit=p_unit,
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
dependency=p_dep, dependency_value=p_dep_val, value=p_val)
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
dependency=p_dep, dependency_value=p_dep_val, value=p_val)

prop_b = Property(name=p_name, value_origin=p_origin, unit=p_unit,
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
dependency=p_dep, dependency_value=p_dep_val, value=p_val)
uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
dependency=p_dep, dependency_value=p_dep_val, value=p_val)

self.assertEqual(prop_a, prop_b)

Expand Down
98 changes: 61 additions & 37 deletions test/test_validation.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import unittest
import odml
import os
import sys
import odml.validation
import odml.terminology
from . import test_samplefile as samplefile

try:
from StringIO import StringIO
except ImportError:
from io import StringIO

validate = odml.validation.Validation


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

def test_section_name_readable(self):
"""
Test if section name is not uuid and thus more readable.
"""
doc = odml.Document()
sec = odml.Section("sec", parent=doc)
sec.name = sec.id
res = validate(doc)
self.assertError(res, "Name should be readable")

def test_property_name_readable(self):
"""
Test if property name is not uuid and thus more readable.
"""
doc = odml.Document()
sec = odml.Section("sec", parent=doc)
prop = odml.Property("prop", parent=sec)
prop.name = prop.id
res = validate(doc)
self.assertError(res, "Name should be readable")

def test_standalone_section(self):
"""
Test if standalone section does not return errors if required attributes are correct.
Expand All @@ -152,8 +179,20 @@ def test_standalone_property(self):
prop = odml.Property()
prop.type = ""

for err in validate(prop).errors:
assert not err.is_error
assert len(list(filter(lambda x: x.is_error, validate(prop).errors))) == 0

def test_section_init(self):
"""
Test validation errors printed to stdout on section init.
"""
val_errs = StringIO()

old_stdout = sys.stdout
sys.stdout = val_errs
odml.Section(name="sec", type=None)
sys.stdout = old_stdout

assert "Section type undefined" in val_errs.getvalue()

def test_prop_string_values(self):
"""
Expand All @@ -172,8 +211,8 @@ def test_prop_string_values(self):

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

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

sec_type_undefined_err = False
sec_type_empty_err = False

for err in validate(doc).errors:
if err.msg == "Section type undefined" and err.obj.name == "sec_type_undefined":
sec_type_undefined_err = True
elif err.msg == "Section type undefined" and err.obj.name == "sec_type_empty":
sec_type_empty_err = True

assert sec_type_undefined_err
assert sec_type_empty_err
assert len(list(filter(
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_undefined",
validate(doc).errors))) > 0
assert len(list(filter(
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_empty",
validate(doc).errors))) > 0

def test_load_dtypes_xml(self):
"""
Expand Down Expand Up @@ -298,17 +332,12 @@ def test_load_section_json(self):
path = os.path.join(self.dir_path, "resources", "validation_section.json")
doc = odml.load(path, "JSON")

sec_type_undefined_err = False
sec_type_empty_err = False

for err in validate(doc).errors:
if err.msg == "Section type undefined" and err.obj.name == "sec_type_undefined":
sec_type_undefined_err = True
elif err.msg == "Section type undefined" and err.obj.name == "sec_type_empty":
sec_type_empty_err = True

assert sec_type_undefined_err
assert sec_type_empty_err
assert len(list(filter(
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_undefined",
validate(doc).errors))) > 0
assert len(list(filter(
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_empty",
validate(doc).errors))) > 0

def test_load_dtypes_json(self):
"""
Expand Down Expand Up @@ -377,17 +406,12 @@ def test_load_section_yaml(self):
path = os.path.join(self.dir_path, "resources", "validation_section.yaml")
doc = odml.load(path, "YAML")

sec_type_undefined_err = False
sec_type_empty_err = False

for err in validate(doc).errors:
if err.msg == "Section type undefined" and err.obj.name == "sec_type_undefined":
sec_type_undefined_err = True
elif err.msg == "Section type undefined" and err.obj.name == "sec_type_empty":
sec_type_empty_err = True

assert sec_type_undefined_err
assert sec_type_empty_err
assert len(list(filter(
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_undefined",
validate(doc).errors))) > 0
assert len(list(filter(
lambda x: x.msg == "Section type undefined" and x.obj.name == "sec_type_empty",
validate(doc).errors))) > 0

def test_load_dtypes_yaml(self):
"""
Expand Down