diff --git a/README.md b/README.md index a6f4c875..3bb6c82a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -![Travis build](https://travis-ci.org/G-Node/python-odml.svg?branch=master) +[![Travis build](https://travis-ci.org/G-Node/python-odml.svg?branch=master)](https://travis-ci.org/G-Node/python-odml) [![Build status](https://ci.appveyor.com/api/projects/status/br7pe6atlwdg5618/branch/master?svg=true)](https://ci.appveyor.com/project/G-Node/python-odml/branch/master) -![Test coverage](https://coveralls.io/repos/github/G-Node/python-odml/badge.svg?branch=master) +[![Test coverage](https://coveralls.io/repos/github/G-Node/python-odml/badge.svg?branch=master)](https://coveralls.io/github/G-Node/python-odml) [![PyPI version](https://img.shields.io/pypi/v/odml.svg)](https://pypi.org/project/odML/) [![Read the Docs](https://img.shields.io/readthedocs/python-odml)](https://python-odml.readthedocs.io/en/latest/) diff --git a/doc/tutorial.rst b/doc/tutorial.rst index aa038d7b..a50d8d97 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -70,8 +70,9 @@ experimental project and complements the special needs of your laboratory. The code for the example odML files, which we use within this tutorial is part of the documentation package (see doc/example_odMLs/). -A summary of available odML terminologies and templates can be found `here -`_. +A summary of available odML terminologies and templates can be found at the G-Node `odML terminology +`_ and `odML template +`_ pages. ------------------------------------------------------------------------------- @@ -311,7 +312,6 @@ following command:: As expected from the Document printout our example contains two Sections. The printout and attributes of a Section are explained in the next chapter. - The Sections ------------ @@ -553,6 +553,18 @@ returned list will have no affect on the actual Property values. If you want to make changes to a Property value, either use the ``append``, ``extend`` and ``remove`` methods or assign a new value list to the property. +Printing overviews to navigate the contents of an odML document +--------------------------------------------------------------- + +The odML entities ``Property``, ``Section`` and ``Document`` feature +a method that allows to print a tree-like representation of +all child entities to get an overview of the file structure. + + >>> MYodML.pprint() + >>> sec = MYodML['TheCrew'] + >>> sec.pprint() + >>> prop = odmlEX['TheCrew'].properties['NameCrewMembers'] + >>> prop.pprint() ------------------------------------------------------------------------------- @@ -930,6 +942,48 @@ Also note that any style that is saved with an odML document will be lost, when document is loaded again and changes to the content are added. In this case the required style needs to be specified again when saving the changed file as described above. + +Defining and working with feature cardinality +--------------------------------------------- + +The odML format allows users to define a cardinality for +the number of subsections and properties of Sections and +the number of values a Property might have. + +A cardinality is checked when it is set, when its target is +set and when a document is saved or loaded. If a specific +cardinality is violated, a corresponding warning will be printed. + +Setting a cardinality +********************* + +A cardinality can be set for sections or properties of sections +or for values of properties. By default every cardinality is None, +but it can be set to a defined minimal and/or a maximal number of +an element. + +A cardinality is set via its convenience method: + + >>> # Set the cardinality of the properties of a Section 'sec' to + >>> # a maximum of 5 elements. + >>> sec = odml.Section(name="cardinality", type="test") + >>> sec.set_properties_cardinality(max_val=5) + + >>> # Set the cardinality of the subsections of Section 'sec' to + >>> # a minimum of one and a maximum of 2 elements. + >>> sec.set_sections_cardinality(min_val=1, max_val=2) + + >>> # Set the cardinality of the values of a Property 'prop' to + >>> # a minimum of 1 element. + >>> prop = odml.Property(name="cardinality") + >>> prop.set_values_cardinality(min_val=1) + + >>> # Re-set the cardinality of the values of a Property 'prop' to not set. + >>> prop.set_values_cardinality() + >>> # or + >>> prop.val_cardinality = None + + Advanced knowledge on Values ---------------------------- diff --git a/odml/base.py b/odml/base.py index f28644d2..6599696b 100644 --- a/odml/base.py +++ b/odml/base.py @@ -2,6 +2,7 @@ """ This module provides base classes for functionality common to odML objects. """ +import copy import posixpath try: @@ -36,9 +37,10 @@ def __eq__(self, obj): return False for key in self._format: - if key == "id" or key == "oid": + if key in ["id", "oid"]: continue - elif getattr(self, key) != getattr(obj, key): + + if getattr(self, key) != getattr(obj, key): return False return True @@ -87,7 +89,6 @@ def clone(self, children=True): from this class. """ # TODO don't we need some recursion / deepcopy here? - import copy obj = copy.copy(self) return obj @@ -149,6 +150,8 @@ def __contains__(self, key): if (hasattr(obj, "name") and obj.name == key) or key == obj: return True + return False + def __eq__(self, obj): """ SmartList attributes of 'sections' and 'properties' are @@ -292,7 +295,7 @@ def extend(self, sec_list): if not isinstance(sec, BaseSection): raise ValueError("Can only extend objects of type Section.") - elif isinstance(sec, BaseSection) and sec.name in self._sections: + if isinstance(sec, BaseSection) and sec.name in self._sections: raise KeyError("Section with name '%s' already exists." % sec.name) for sec in sec_list: @@ -356,9 +359,9 @@ def iterproperties(self, max_depth=None, filter_func=lambda x: True): iterable. Yields iterable if function returns True :type filter_func: function """ - for sec in [s for s in self.itersections(max_depth=max_depth, - yield_self=True)]: - if hasattr(sec, "properties"): # not to fail if odml.Document + for sec in list(self.itersections(max_depth=max_depth, yield_self=True)): + # Avoid fail with an odml.Document + if hasattr(sec, "properties"): for i in sec.properties: if filter_func(i): yield i @@ -380,7 +383,7 @@ def itervalues(self, max_depth=None, filter_func=lambda x: True): iterable. Yields iterable if function returns True :type filter_func: function """ - for prop in [p for p in self.iterproperties(max_depth=max_depth)]: + for prop in list(self.iterproperties(max_depth=max_depth)): if filter_func(prop.values): yield prop.values @@ -478,9 +481,10 @@ def _get_section_by_path(self, path): if found: return found._get_section_by_path("/".join(pathlist[1:])) + raise ValueError("Section named '%s' does not exist" % pathlist[0]) - else: - return self._match_iterable(self.sections, pathlist[0]) + + return self._match_iterable(self.sections, pathlist[0]) def find(self, key=None, type=None, findAll=False, include_subtype=False): """ diff --git a/odml/doc.py b/odml/doc.py index 46a6cfd2..29f366a0 100644 --- a/odml/doc.py +++ b/odml/doc.py @@ -122,6 +122,20 @@ def parent(self): """ The parent of a document is always None. """ return None + @property + def origin_file_name(self): + """ + If available, the file name from where the document has been loaded. + Will not be serialized to file when saving the document. + """ + return self._origin_file_name + + @origin_file_name.setter + def origin_file_name(self, new_value): + if not new_value: + new_value = None + self._origin_file_name = new_value + def finalize(self): """ This needs to be called after the document is set up from parsing diff --git a/odml/property.py b/odml/property.py index 2c3b6be5..7ed6f740 100644 --- a/odml/property.py +++ b/odml/property.py @@ -253,7 +253,8 @@ def parent(self): def parent(self, new_parent): if new_parent is None and self._parent is None: return - elif new_parent is None and self._parent is not None: + + if new_parent is None and self._parent is not None: self._parent.remove(self) self._parent = None elif self._validate_parent(new_parent): @@ -319,7 +320,8 @@ def _validate_values(self, values): return False return True - def _convert_value_input(self, new_value): + @staticmethod + def _convert_value_input(new_value): """ This method ensures, that the passed new value is a list. If new_value is a string, it will convert it to a list of @@ -403,14 +405,12 @@ def values(self, new_value): new_value = odml_tuple_import(t_count, new_value) if not self._validate_values(new_value): + msg = "odml.Property.values: passed values are not of consistent type" if self._dtype in ("date", "time", "datetime"): req_format = dtypes.default_values(self._dtype) - msg = "odml.Property.values: passed values are not of consistent type " - msg += "\'%s\'! Format should be \'%s\'." % (self._dtype, req_format) - raise ValueError(msg) - else: - msg = "odml.Property.values: passed values are not of consistent type!" - raise ValueError(msg) + msg += " \'%s\'! Format should be \'%s\'." % (self._dtype, req_format) + raise ValueError(msg) + self._values = [dtypes.get(v, self.dtype) for v in new_value] # Validate and inform user if the current values cardinality is violated @@ -714,10 +714,10 @@ def get_merged_equivalent(self): Return the merged object (i.e. if the parent section is linked to another one, return the corresponding property of the linked section) or None. """ - if self.parent is None or self.parent._merged is None: + if self.parent is None or not self.parent.is_merged: return None - return self.parent._merged.contains(self) + return self.parent.get_merged_equivalent().contains(self) @inherit_docstring def get_terminology_equivalent(self): @@ -841,26 +841,16 @@ def pprint(self, indent=2, max_length=80, current_depth=-1): def export_leaf(self): """ - Export only the path from this property to the root. - Include all properties of parent sections. - - :returns: cloned odml tree to the root of the current document. - """ - curr = self.parent - par = self.parent - child = self.parent - - while curr is not None: - par = curr.clone(children=False, keep_id=True) - if curr != self.parent: - par.append(child) - if hasattr(curr, 'properties'): - if curr == self.parent: - par.append(self.clone(keep_id=True)) - else: - for prop in curr.properties: - par.append(prop.clone(keep_id=True)) - child = par - curr = curr.parent - - return par + Export the path including all direct parents from this Property + to the root of the document. Section properties are included, + Subsections are not included. + + :returns: Cloned odml tree to the root of the current document. + """ + export = self + if export.parent: + # Section.export_leaf will take care of the full export and + # include the current Property. + export = export.parent.export_leaf() + + return export diff --git a/odml/section.py b/odml/section.py index 8e8f018c..db431adb 100644 --- a/odml/section.py +++ b/odml/section.py @@ -54,7 +54,6 @@ class BaseSection(base.Sectionable): """ type = None - reference = None # the *import* property _link = None _include = None _merged = None @@ -328,7 +327,8 @@ def parent(self): def parent(self, new_parent): if new_parent is None and self._parent is None: return - elif new_parent is None and self._parent is not None: + + if new_parent is None and self._parent is not None: self._parent.remove(self) self._parent = None elif self._validate_parent(new_parent): @@ -341,7 +341,8 @@ def parent(self, new_parent): "odml.Section.parent: passed value is not of consistent type!" "\nodml.Document or odml.Section expected") - def _validate_parent(self, new_parent): + @staticmethod + def _validate_parent(new_parent): """ Checks whether a provided object is a valid odml.Section or odml.Document.. @@ -402,9 +403,9 @@ def set_sections_cardinality(self, min_val=None, max_val=None): Sets the Sections cardinality of a Section. :param min_val: Required minimal number of values elements. None denotes - no restrictions on values elements minimum. Default is None. + no restrictions on sections elements minimum. Default is None. :param max_val: Allowed maximal number of values elements. None denotes - no restrictions on values elements maximum. Default is None. + no restrictions on sections elements maximum. Default is None. """ self.sec_cardinality = (min_val, max_val) @@ -455,9 +456,9 @@ def set_properties_cardinality(self, min_val=None, max_val=None): Sets the Properties cardinality of a Section. :param min_val: Required minimal number of values elements. None denotes - no restrictions on values elements minimum. Default is None. + no restrictions on properties elements minimum. Default is None. :param max_val: Allowed maximal number of values elements. None denotes - no restrictions on values elements maximum. Default is None. + no restrictions on properties elements maximum. Default is None. """ self.prop_cardinality = (min_val, max_val) @@ -521,16 +522,16 @@ def extend(self, obj_list): # Make sure only Sections and Properties with unique names will be added. for obj in obj_list: if not isinstance(obj, BaseSection) and not isinstance(obj, BaseProperty): - raise ValueError("odml.Section.extend: " - "Can only extend sections and properties.") + msg = "odml.Section.extend: Can only extend sections and properties." + raise ValueError(msg) - elif isinstance(obj, BaseSection) and obj.name in self.sections: - raise KeyError("odml.Section.extend: " - "Section with name '%s' already exists." % obj.name) + if isinstance(obj, BaseSection) and obj.name in self.sections: + msg = "odml.Section.extend: Section with name '%s' already exists." % obj.name + raise KeyError(msg) - elif isinstance(obj, BaseProperty) and obj.name in self.properties: - raise KeyError("odml.Section.extend: " - "Property with name '%s' already exists." % obj.name) + if isinstance(obj, BaseProperty) and obj.name in self.properties: + msg = "odml.Section.extend: Property with name '%s' already exists." % obj.name + raise KeyError(msg) for obj in obj_list: self.append(obj) @@ -613,13 +614,14 @@ def contains(self, obj): if isinstance(obj, BaseSection): return super(BaseSection, self).contains(obj) - elif isinstance(obj, BaseProperty): + if isinstance(obj, BaseProperty): for i in self._props: if obj.name == i.name: return i - else: - raise ValueError("odml.Section.contains:" - "Section or Property object expected.") + + return None + + raise ValueError("odml.Section.contains: Section or Property object expected.") def merge_check(self, source_section, strict=True): """ diff --git a/odml/tools/converters/format_converter.py b/odml/tools/converters/format_converter.py index b12258c1..a3593d26 100644 --- a/odml/tools/converters/format_converter.py +++ b/odml/tools/converters/format_converter.py @@ -79,7 +79,7 @@ def convert(cls, args=None): parser.add_argument("-r", "--recursive", action="store_true", help="Enable converting files from subdirectories") args = parser.parse_args(args) - recursive = True if args.recursive else False + recursive = bool(args.recursive) cls.convert_dir(args.input_dir, args.output_dir, recursive, args.result_format) @classmethod diff --git a/odml/tools/converters/version_converter.py b/odml/tools/converters/version_converter.py index 804fc68a..bd05da39 100644 --- a/odml/tools/converters/version_converter.py +++ b/odml/tools/converters/version_converter.py @@ -12,6 +12,8 @@ from lxml import etree as ET +from ..parser_utils import ParserException + from ...format import Document, Section, Property from ...info import FORMAT_VERSION from ...terminology import Terminologies, REPOSITORY_BASE @@ -52,7 +54,7 @@ def _parse_xml(self): tree = ET.parse(self.filename, parser) else: msg = "Cannot parse provided file object '%s'." % self.filename - raise Exception(msg) + raise ParserException(msg) return tree diff --git a/odml/tools/odmlparser.py b/odml/tools/odmlparser.py index e2cf2d18..a9424474 100644 --- a/odml/tools/odmlparser.py +++ b/odml/tools/odmlparser.py @@ -173,7 +173,7 @@ def from_file(self, file, doc_format=None): self.doc = par.from_file(file) return self.doc - elif self.parser == 'YAML': + if self.parser == 'YAML': with open(file) as yaml_data: try: yaml.SafeLoader.add_constructor("tag:yaml.org,2002:python/unicode", @@ -186,10 +186,10 @@ def from_file(self, file, doc_format=None): par = DictReader(show_warnings=self.show_warnings) self.doc = par.to_odml(self.parsed_doc) # Provide original file name via the in memory document - self.doc._origin_file_name = basename(file) + self.doc.origin_file_name = basename(file) return self.doc - elif self.parser == 'JSON': + if self.parser == 'JSON': with open(file) as json_data: try: self.parsed_doc = json.load(json_data) @@ -200,10 +200,10 @@ def from_file(self, file, doc_format=None): par = DictReader(show_warnings=self.show_warnings) self.doc = par.to_odml(self.parsed_doc) # Provide original file name via the in memory document - self.doc._origin_file_name = basename(file) + self.doc.origin_file_name = basename(file) return self.doc - elif self.parser == 'RDF': + if self.parser == 'RDF': if not doc_format: raise ValueError("Format of the rdf file was not specified") @@ -228,7 +228,7 @@ def from_string(self, string, doc_format=None): self.doc = xmlparser.XMLReader().from_string(string) return self.doc - elif self.parser == 'YAML': + if self.parser == 'YAML': try: self.parsed_doc = yaml.safe_load(string) except yaml.parser.ParserError as err: @@ -238,7 +238,7 @@ def from_string(self, string, doc_format=None): self.doc = DictReader().to_odml(self.parsed_doc) return self.doc - elif self.parser == 'JSON': + if self.parser == 'JSON': try: self.parsed_doc = json.loads(string) except ValueError as err: # Python 2 does not support JSONDecodeError @@ -248,7 +248,7 @@ def from_string(self, string, doc_format=None): self.doc = DictReader().to_odml(self.parsed_doc) return self.doc - elif self.parser == 'RDF': + if self.parser == 'RDF': if not doc_format: raise ValueError("Format of the rdf file was not specified") diff --git a/odml/tools/parser_utils.py b/odml/tools/parser_utils.py index 66d17ead..dcbc63c2 100644 --- a/odml/tools/parser_utils.py +++ b/odml/tools/parser_utils.py @@ -26,14 +26,12 @@ class ParserException(Exception): """ Exception wrapper used by various odML parsers. """ - pass class InvalidVersionException(ParserException): """ Exception wrapper to indicate a non-compatible odML version. """ - pass def odml_tuple_export(odml_tuples): diff --git a/odml/tools/rdf_converter.py b/odml/tools/rdf_converter.py index 9fb010c3..205ec7c6 100644 --- a/odml/tools/rdf_converter.py +++ b/odml/tools/rdf_converter.py @@ -184,8 +184,8 @@ def save_document(self, doc, curr_node=None): # If available, add the documents' filename to the document node # so we can identify where the data came from. - if hasattr(doc, "_origin_file_name"): - curr_lit = Literal(doc._origin_file_name) + if hasattr(doc, "origin_file_name"): + curr_lit = Literal(doc.origin_file_name) self.graph.add((curr_node, ODML_NS.hasFileName, curr_lit)) for k in fmt.rdf_map_keys: @@ -195,7 +195,8 @@ def save_document(self, doc, curr_node=None): # Ignore an "id" entry, it has already been used to create the node itself. if k == "id" or not curr_val: continue - elif k == "repository": + + if k == "repository": self.save_repository_node(curr_node, curr_pred, curr_val) elif k == "sections": # generating nodes for child sections @@ -233,7 +234,8 @@ def save_section(self, sec, curr_node): # Ignore an "id" entry, it has already been used to create the node itself. if k == "id" or not curr_val: continue - elif k == "repository": + + if k == "repository": self.save_repository_node(curr_node, curr_pred, curr_val) # generating nodes for sections and properties @@ -269,7 +271,8 @@ def save_property(self, prop, curr_node): # is only accessed via its non deprecated property "values". if k == "id" or not curr_val: continue - elif k == "value": + + if k == "value": # generating nodes for Property values self.save_odml_values(curr_node, curr_pred, curr_val) else: @@ -383,7 +386,7 @@ def from_file(self, filename, doc_format): docs = self.to_odml() for curr_doc in docs: # Provide original file name via the document - curr_doc._origin_file_name = os.path.basename(filename) + curr_doc.origin_file_name = os.path.basename(filename) return docs diff --git a/odml/tools/xmlparser.py b/odml/tools/xmlparser.py index e23359af..f499adad 100644 --- a/odml/tools/xmlparser.py +++ b/odml/tools/xmlparser.py @@ -156,6 +156,7 @@ def save_element(curr_el): val = getattr(curr_el, fmt.map(k)) if val is None: continue + if isinstance(fmt, ofmt.Property.__class__) and k == "value": # Custom odML tuples require special handling for save loading from file. if curr_el.dtype and curr_el.dtype.endswith("-tuple") and val: @@ -274,10 +275,12 @@ def _handle_version(root): """ if root.tag != 'odML': raise ParserException("Expecting tag but got <%s>.\n" % root.tag) - elif 'version' not in root.attrib: - raise ParserException("Could not find format version attribute " - "in tag.\n") - elif root.attrib['version'] != FORMAT_VERSION: + + if 'version' not in root.attrib: + msg = "Could not find format version attribute in tag.\n" + raise ParserException(msg) + + if root.attrib['version'] != FORMAT_VERSION: msg = ("Cannot parse odML document with format version '%s'. \n" "\tUse the 'VersionConverter' from 'odml.tools.converters' " "to import previous odML formats." @@ -304,7 +307,8 @@ def from_file(self, xml_file): # Provide original file name via the in memory document if isinstance(xml_file, unicode): - doc._origin_file_name = basename(xml_file) + doc.origin_file_name = basename(xml_file) + return doc def from_string(self, string): @@ -513,13 +517,14 @@ def parse_property(self, root, fmt): if __name__ == '__main__': - from optparse import OptionParser + import argparse import odml.tools.dumper as dumper - parser = OptionParser() - (options, args) = parser.parse_args() + args = sys.argv[1:] - if len(args) < 1: - parser.print_help() - else: - dumper.dump_doc(load(args[0])) + desc = "Print content of an odml xml file to the stdout" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument("odml_file", help="Path to odml xml file") + args = parser.parse_args(args) + + dumper.dump_doc(load(args.odml_file)) diff --git a/test/test_bugs.py b/test/test_bugs.py index 48bce81e..10380442 100644 --- a/test/test_bugs.py +++ b/test/test_bugs.py @@ -1,6 +1,7 @@ -import odml import unittest +import odml + from odml.terminology import REPOSITORY diff --git a/test/test_doc.py b/test/test_doc.py index 984f1348..6091687e 100644 --- a/test/test_doc.py +++ b/test/test_doc.py @@ -1,9 +1,7 @@ import datetime import os import unittest -import tempfile -import odml.terminology -from hashlib import md5 + try: from urllib.request import pathname2url except ImportError: @@ -98,8 +96,7 @@ def test_date(self): def test_get_terminology_equivalent(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - repo_file = os.path.join(dir_path, "resources", - "local_repository_file_v1.1.xml") + repo_file = os.path.join(dir_path, "resources", "local_repository_file_v1.1.xml") local_url = "file://%s" % pathname2url(repo_file) doc = Document(repository=local_url) @@ -112,32 +109,6 @@ def test_get_terminology_equivalent(self): doc.repository = None self.assertIsNone(doc.get_terminology_equivalent()) - def test_terminology_refresh(self): - - cache_dir = os.path.join(tempfile.gettempdir(), "odml.cache") - url = "https://terminologies.g-node.org/v1.1/terminologies.xml" - term_doc = odml.terminology.load(url) - - terms = [] - for sec in term_doc.sections: - terms += ['.'.join([md5(sec.include.encode()).hexdigest(), os.path.basename(sec.include)])] - - before = datetime.datetime.now() - - for loaded_file in os.listdir(cache_dir): - for term in terms: - if term in loaded_file: - assert datetime.datetime.fromtimestamp( - os.path.getmtime(os.path.join(cache_dir, loaded_file))) < before - - odml.terminology.refresh(url) - - for replaced_file in os.listdir(cache_dir): - for term in terms: - if term in replaced_file: - assert datetime.datetime.fromtimestamp( - os.path.getmtime(os.path.join(cache_dir, replaced_file))) > before - def test_append(self): doc = Document() self.assertListEqual(doc.sections, []) @@ -326,14 +297,14 @@ def test_create_section(self): self.assertEqual(len(root.sections), 0) name = "subsec" - type = "subtype" + sec_type = "subtype" oid = "79b613eb-a256-46bf-84f6-207df465b8f7" - subsec = root.create_section(name, type, oid) + subsec = root.create_section(name, sec_type, oid) self.assertEqual(len(root.sections), 1) self.assertEqual(subsec.parent, root) self.assertEqual(root.sections[name], subsec) - self.assertEqual(root.sections[name].type, type) + self.assertEqual(root.sections[name].type, sec_type) self.assertEqual(root.sections[name].oid, oid) name = "othersec" diff --git a/test/test_dtypes.py b/test/test_dtypes.py index 2d54a03a..a16ff253 100644 --- a/test/test_dtypes.py +++ b/test/test_dtypes.py @@ -8,7 +8,7 @@ class TestTypes(unittest.TestCase): - def assertLocalRegExp(self, text, regular_expression): + def assert_local_regexp(self, text, regular_expression): """ Python 2 is dead and assertRegexpMatches is deprecated and will be removed, but keep compatibility until py 2 support is @@ -20,9 +20,6 @@ def assertLocalRegExp(self, text, regular_expression): else: self.assertRegex(text, regular_expression) - def setUp(self): - pass - def test_valid_type(self): # Test None self.assertTrue(typ.valid_type(None)) @@ -32,7 +29,7 @@ def test_valid_type(self): self.assertTrue(typ.valid_type(curr_type), "Invalid DType %s" % curr_type) # Test that provided shorthand dtypes return as valid dtypes. - for curr_shorthand in typ._dtype_map.keys(): + for curr_shorthand in typ._dtype_map: self.assertTrue(typ.valid_type(curr_shorthand), "Invalid dtype shorthand %s" % curr_shorthand) @@ -49,9 +46,9 @@ def test_date(self): self.assertIsInstance(typ.date_get(None), datetime.date) self.assertIsInstance(typ.date_get(""), datetime.date) - re = "^[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])$" - self.assertLocalRegExp(typ.date_get(None).strftime(typ.FORMAT_DATE), re) - self.assertLocalRegExp(typ.date_get("").strftime(typ.FORMAT_DATE), re) + reg = "^[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])$" + self.assert_local_regexp(typ.date_get(None).strftime(typ.FORMAT_DATE), reg) + self.assert_local_regexp(typ.date_get("").strftime(typ.FORMAT_DATE), reg) date = datetime.date(2011, 12, 1) date_string = '2011-12-01' @@ -81,9 +78,9 @@ def test_time(self): self.assertIsInstance(typ.time_get(None), datetime.time) self.assertIsInstance(typ.time_get(""), datetime.time) - re = "^[0-5][0-9]:[0-5][0-9]:[0-5][0-9]$" - self.assertLocalRegExp(typ.time_get(None).strftime(typ.FORMAT_TIME), re) - self.assertLocalRegExp(typ.time_get("").strftime(typ.FORMAT_TIME), re) + reg = "^[0-5][0-9]:[0-5][0-9]:[0-5][0-9]$" + self.assert_local_regexp(typ.time_get(None).strftime(typ.FORMAT_TIME), reg) + self.assert_local_regexp(typ.time_get("").strftime(typ.FORMAT_TIME), reg) time = datetime.time(12, 34, 56) time_string = '12:34:56' @@ -113,10 +110,9 @@ def test_datetime(self): self.assertIsInstance(typ.datetime_get(None), datetime.datetime) self.assertIsInstance(typ.datetime_get(""), datetime.datetime) - re = "^[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1]) " \ - "[0-5][0-9]:[0-5][0-9]:[0-5][0-9]$" - self.assertLocalRegExp(typ.datetime_get(None).strftime(typ.FORMAT_DATETIME), re) - self.assertLocalRegExp(typ.datetime_get("").strftime(typ.FORMAT_DATETIME), re) + reg = "^[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1]) [0-5][0-9]:[0-5][0-9]:[0-5][0-9]$" + self.assert_local_regexp(typ.datetime_get(None).strftime(typ.FORMAT_DATETIME), reg) + self.assert_local_regexp(typ.datetime_get("").strftime(typ.FORMAT_DATETIME), reg) date = datetime.datetime(2011, 12, 1, 12, 34, 56) date_string = '2011-12-01 12:34:56' diff --git a/test/test_dumper.py b/test/test_dumper.py index 24db6b50..7453089a 100644 --- a/test/test_dumper.py +++ b/test/test_dumper.py @@ -16,23 +16,23 @@ def setUp(self): s_type = "type" self.doc = odml.Document(author='Rave', version='1.0') - s1 = odml.Section(name='Cell', type=s_type) - p1 = odml.Property(name='Type', values='Rechargeable') - s1.append(p1) + sec1 = odml.Section(name='Cell', type=s_type) + prop1 = odml.Property(name='Type', values='Rechargeable') + sec1.append(prop1) - s2 = odml.Section(name='Electrolyte', type=s_type) - p2 = odml.Property(name='Composition', values='Ni-Cd') - s2.append(p2) - s1.append(s2) + sec2 = odml.Section(name='Electrolyte', type=s_type) + prop2 = odml.Property(name='Composition', values='Ni-Cd') + sec2.append(prop2) + sec1.append(sec2) - s3 = odml.Section(name='Electrode', type=s_type) - p3 = odml.Property(name='Material', values='Nickel') - p4 = odml.Property(name='Models', values=['AA', 'AAA']) - s3.append(p3) - s3.append(p4) - s2.append(s3) + sec3 = odml.Section(name='Electrode', type=s_type) + prop3 = odml.Property(name='Material', values='Nickel') + prop4 = odml.Property(name='Models', values=['AA', 'AAA']) + sec3.append(prop3) + sec3.append(prop4) + sec2.append(sec3) - self.doc.append(s1) + self.doc.append(sec1) def test_dump_doc(self): # Capture the output printed by the functions to STDOUT, and use it for @@ -48,15 +48,14 @@ def test_dump_doc(self): # Reset stdout sys.stdout = sys.__stdout__ - expected_output = [] - expected_output.append("*Cell (type='type')") - expected_output.append(":Type (values=Rechargeable, dtype='string')") - expected_output.append("*Electrolyte (type='type')") - expected_output.append(":Composition (values=Ni-Cd, dtype='string')") - expected_output.append("*Electrode (type='type')") - expected_output.append(":Material (values=Nickel, dtype='string')") - expected_output.append(":Models (values=[AA,AAA], dtype='string')") + expected_output = ["*Cell (type='type')", + ":Type (values=Rechargeable, dtype='string')", + "*Electrolyte (type='type')", + ":Composition (values=Ni-Cd, dtype='string')", + "*Electrode (type='type')", + ":Material (values=Nickel, dtype='string')", + ":Models (values=[AA,AAA], dtype='string')"] self.assertEqual(len(output), len(expected_output)) - for i in range(len(output)): + for i, _ in enumerate(output): self.assertEqual(output[i], expected_output[i]) diff --git a/test/test_fileio.py b/test/test_fileio.py index c89ecc8d..47c6e716 100644 --- a/test/test_fileio.py +++ b/test/test_fileio.py @@ -10,7 +10,6 @@ class TestTypes(unittest.TestCase): - # TODO :- Write tests for JSONParser once it's completed. def setUp(self): self.dir_path = os.path.dirname(os.path.realpath(__file__)) @@ -39,4 +38,3 @@ def test_invalid_parser(self): with self.assertRaises(NotImplementedError): odml.display(doc, 'html') - diff --git a/test/test_find_section.py b/test/test_find_section.py index 80c6363c..54d91245 100644 --- a/test/test_find_section.py +++ b/test/test_find_section.py @@ -1,4 +1,5 @@ import unittest + from odml import Section diff --git a/test/test_format_converter.py b/test/test_format_converter.py index 589cdfa5..a89f34e4 100644 --- a/test/test_format_converter.py +++ b/test/test_format_converter.py @@ -141,4 +141,3 @@ def test_check_io_directory(self): FC._check_input_output_directory(in_dir, "/not_valid_path") self.assertNotRaises(FC._check_input_output_directory(in_dir, None)) self.assertNotRaises(FC._check_input_output_directory(in_dir, out_dir)) - diff --git a/test/test_infer_type.py b/test/test_infer_type.py index 4be47578..37d96051 100644 --- a/test/test_infer_type.py +++ b/test/test_infer_type.py @@ -1,66 +1,66 @@ import unittest -import sys + from datetime import datetime as dt, date, time + from odml import Property, Section, Document from odml.tools.xmlparser import XMLReader, XMLWriter +try: + unicode = unicode +except NameError: + unicode = str + class TestInferType(unittest.TestCase): def test_string(self): - p = Property("test", value="somestring") - assert(p.dtype == "string") - if sys.version_info < (3, 0): - assert isinstance(p.values[0], unicode) - else: - assert isinstance(p.values[0], str) + prop = Property("test", value="some_string") + self.assertEqual(prop.dtype, "string") + self.assertIsInstance(prop.values[0], unicode) def test_text(self): - p = Property("test", value="some\nstring") - assert(p.dtype == "text") - if sys.version_info < (3, 0): - assert isinstance(p.values[0], unicode) - else: - assert isinstance(p.values[0], str) + prop = Property("test", value="some\nstring") + self.assertEqual(prop.dtype, "text") + self.assertIsInstance(prop.values[0], unicode) def test_int(self): - p = Property("test", value=111) - assert(p.dtype == "int") - assert isinstance(p.values[0], int) + prop = Property("test", value=111) + self.assertEqual(prop.dtype, "int") + self.assertIsInstance(prop.values[0], int) def test_float(self): - p = Property("test", value=3.14) - assert(p.dtype == "float") - assert isinstance(p.values[0], float) + prop = Property("test", value=3.14) + self.assertEqual(prop.dtype, "float") + self.assertIsInstance(prop.values[0], float) def test_datetime(self): - p = Property("test", value=dt.now()) - assert(p.dtype == "datetime") - assert isinstance(p.values[0], dt) + prop = Property("test", value=dt.now()) + self.assertEqual(prop.dtype, "datetime") + self.assertIsInstance(prop.values[0], dt) def test_date(self): - p = Property("test", dt.now().date()) - assert(p.dtype == "date") - assert isinstance(p.values[0], date) + prop = Property("test", dt.now().date()) + self.assertEqual(prop.dtype, "date") + self.assertIsInstance(prop.values[0], date) def test_time(self): - p = Property("test", value=dt.now().time()) - assert(p.dtype == "time") - assert isinstance(p.values[0], time) + prop = Property("test", value=dt.now().time()) + self.assertEqual(prop.dtype, "time") + self.assertIsInstance(prop.values[0], time) def test_boolean(self): - p = Property("test", True) - assert(p.dtype == "boolean") - assert isinstance(p.values[0], bool) + prop = Property("test", True) + self.assertEqual(prop.dtype, "boolean") + self.assertIsInstance(prop.values[0], bool) - p = Property("test", False) - assert(p.dtype == "boolean") - assert isinstance(p.values[0], bool) + prop = Property("test", False) + self.assertEqual(prop.dtype, "boolean") + self.assertIsInstance(prop.values[0], bool) def test_read_write(self): doc = Document("author") - sec = Section("name", "type") - doc.append(sec) + sec = Section("name", "type", parent=doc) + sec.append(Property("strprop", "somestring")) sec.append(Property("txtprop", "some\ntext")) sec.append(Property("intprop", 200)) @@ -69,47 +69,40 @@ def test_read_write(self): sec.append(Property("dateprop", dt.now().date())) sec.append(Property("timeprop", dt.now().time())) sec.append(Property("boolprop", True)) - if sys.version_info < (3, 0): - str_doc = unicode(XMLWriter(doc)) - else: - str_doc = str(XMLWriter(doc)) + + str_doc = unicode(XMLWriter(doc)) + new_doc = XMLReader().from_string(str_doc) new_sec = new_doc.sections[0] - p = new_sec.properties["strprop"] - assert(p.dtype == "string") - if sys.version_info < (3, 0): - assert isinstance(p.values[0], unicode) - else: - assert isinstance(p.values[0], str) - - p = new_sec.properties["txtprop"] - assert(p.dtype == "text") - if sys.version_info < (3, 0): - assert isinstance(p.values[0], unicode) - else: - assert isinstance(p.values[0], str) - - p = new_sec.properties["intprop"] - assert(p.dtype == "int") - assert isinstance(p.values[0], int) - - p = new_sec.properties["floatprop"] - assert(p.dtype == "float") - assert isinstance(p.values[0], float) - - p = new_sec.properties["datetimeprop"] - assert(p.dtype == "datetime") - assert isinstance(p.values[0], dt) - - p = new_sec.properties["dateprop"] - assert(p.dtype == "date") - assert isinstance(p.values[0], date) - - p = new_sec.properties["timeprop"] - assert(p.dtype == "time") - assert isinstance(p.values[0], time) - - p = new_sec.properties["boolprop"] - assert(p.dtype == "boolean") - assert isinstance(p.values[0], bool) + prop = new_sec.properties["strprop"] + self.assertEqual(prop.dtype, "string") + self.assertIsInstance(prop.values[0], unicode) + + prop = new_sec.properties["txtprop"] + self.assertEqual(prop.dtype, "text") + self.assertIsInstance(prop.values[0], unicode) + + prop = new_sec.properties["intprop"] + self.assertEqual(prop.dtype, "int") + self.assertIsInstance(prop.values[0], int) + + prop = new_sec.properties["floatprop"] + self.assertEqual(prop.dtype, "float") + self.assertIsInstance(prop.values[0], float) + + prop = new_sec.properties["datetimeprop"] + self.assertEqual(prop.dtype, "datetime") + self.assertIsInstance(prop.values[0], dt) + + prop = new_sec.properties["dateprop"] + self.assertEqual(prop.dtype, "date") + self.assertIsInstance(prop.values[0], date) + + prop = new_sec.properties["timeprop"] + self.assertEqual(prop.dtype, "time") + self.assertIsInstance(prop.values[0], time) + + prop = new_sec.properties["boolprop"] + self.assertEqual(prop.dtype, "boolean") + self.assertIsInstance(prop.values[0], bool) diff --git a/test/test_iterators.py b/test/test_iterators.py index 9c17dab2..b2d095f9 100644 --- a/test/test_iterators.py +++ b/test/test_iterators.py @@ -1,92 +1,85 @@ import unittest -from datetime import datetime as dt -from odml import Property, Section, Document -longago = dt.strptime('2013-08-11 09:48:49', "%Y-%m-%d %H:%M:%S") -recently = dt.strptime('2014-02-25 14:42:13', "%Y-%m-%d %H:%M:%S") +from odml import Property, Section, Document class TestValidation(unittest.TestCase): def setUp(self): """ - doc --
--
+ doc --
--
\ - --
--
- + --
--
""" doc = Document("author") - foo = Section("foo", "footype") - doc.append(foo) - foo.append(Property("strprop", "somestring")) - foo.append(Property("txtprop", "some\ntext")) + sec_main = Section("sec_main", "maintype") + doc.append(sec_main) + sec_main.append(Property("strprop", "somestring")) + sec_main.append(Property("txtprop", "some\ntext")) - subfoo = Section("subfoo", "footype") - foo.append(subfoo) - subfoo.append(Property("strprop", "somestring")) - subfoo.append(Property("txtprop", "some\ntext")) + sub_main = Section("sub_main", "maintype") + sec_main.append(sub_main) + sub_main.append(Property("strprop", "somestring")) + sub_main.append(Property("txtprop", "some\ntext")) - bar = Section("bar", "bartype") - foo.append(bar) - bar.append(Property("strprop", "otherstring")) - bar.append(Property("txtprop", "other\ntext")) + sec_branch = Section("sec_branch", "branchtype") + sec_main.append(sec_branch) + sec_branch.append(Property("strprop", "otherstring")) + sec_branch.append(Property("txtprop", "other\ntext")) - subbar = Section("subbar", "bartype") - bar.append(subbar) - subbar.append(Property("strprop", "otherstring")) - subbar.append(Property("txtprop", "other\ntext")) + sub_branch = Section("sub_branch", "branchtype") + sec_branch.append(sub_branch) + sub_branch.append(Property("strprop", "otherstring")) + sub_branch.append(Property("txtprop", "other\ntext")) self.doc = doc def test_itersections(self): - sec_all = self.doc.itersections() - assert(len([s for s in sec_all]) == 4) + sec_all = list(self.doc.itersections()) + self.assertEqual(len(sec_all), 4) - filter_func = lambda x: getattr(x, 'name') == "foo" - sec_filt = self.doc.itersections(filter_func=filter_func) - assert(len([s for s in sec_filt]) == 1) + filter_func = lambda x: getattr(x, "name") == "sec_main" + sec_filtered = list(self.doc.itersections(filter_func=filter_func)) + self.assertEqual(len(sec_filtered), 1) - filter_func = lambda x: getattr(x, 'type').find("bar") > -1 - sec_filt = self.doc.itersections(filter_func=filter_func) - assert(len([s for s in sec_filt]) == 2) + filter_func = lambda x: getattr(x, "type").find("branch") > -1 + sec_filtered = list(self.doc.itersections(filter_func=filter_func)) + self.assertEqual(len(sec_filtered), 2) - sec_filt = self.doc.itersections(max_depth=2) - assert(len([s for s in sec_filt]) == 3) + sec_filtered = list(self.doc.itersections(max_depth=2)) + self.assertEqual(len(sec_filtered), 3) - sec_filt = self.doc.itersections(max_depth=1) - assert(len([s for s in sec_filt]) == 1) + sec_filtered = list(self.doc.itersections(max_depth=1)) + self.assertEqual(len(sec_filtered), 1) - sec_filt = self.doc.itersections(max_depth=0) - assert(len([s for s in sec_filt]) == 0) + sec_filtered = list(self.doc.itersections(max_depth=0)) + self.assertEqual(len(sec_filtered), 0) def test_iterproperties(self): - prop_all = self.doc.iterproperties() - assert(len([p for p in prop_all]) == 8) - - filter_func = lambda x: getattr(x, 'name').find("strprop") > -1 - prop_filt = self.doc.iterproperties(filter_func=filter_func) - assert(len([p for p in prop_filt]) == 4) + prop_all = list(self.doc.iterproperties()) + self.assertEqual(len(prop_all), 8) - prop_filt = self.doc.iterproperties( - filter_func=filter_func, max_depth=2) - assert(len([p for p in prop_filt]) == 3) + filter_func = lambda x: getattr(x, "name").find("strprop") > -1 + prop_filtered = list(self.doc.iterproperties(filter_func=filter_func)) + self.assertEqual(len(prop_filtered), 4) - prop_filt = self.doc.iterproperties(filter_func=filter_func, - max_depth=1) + prop_filtered = list(self.doc.iterproperties(filter_func=filter_func, max_depth=2)) + self.assertEqual(len(prop_filtered), 3) - assert(len([p for p in prop_filt]) == 1) + prop_filtered = list(self.doc.iterproperties(filter_func=filter_func, max_depth=1)) + self.assertEqual(len(prop_filtered), 1) def test_itervalues(self): - val_all = self.doc.itervalues() - assert(len([v for v in val_all]) == 8) + val_all = list(self.doc.itervalues()) + self.assertEqual(len(val_all), 8) filter_func = lambda x: str(x).find("text") > -1 - val_filt = self.doc.itervalues(filter_func=filter_func) - assert(len([v for v in val_filt]) == 4) + val_filtered = list(self.doc.itervalues(filter_func=filter_func)) + self.assertEqual(len(val_filtered), 4) - val_filt = self.doc.itervalues(filter_func=filter_func, max_depth=2) - assert(len([v for v in val_filt]) == 3) + val_filtered = list(self.doc.itervalues(filter_func=filter_func, max_depth=2)) + self.assertEqual(len(val_filtered), 3) - val_filt = self.doc.itervalues(filter_func=filter_func, max_depth=1) - assert(len([v for v in val_filt]) == 1) + val_filtered = list(self.doc.itervalues(filter_func=filter_func, max_depth=1)) + self.assertEqual(len(val_filtered), 1) diff --git a/test/test_property.py b/test/test_property.py index 371c8bc8..1a3cc92c 100644 --- a/test/test_property.py +++ b/test/test_property.py @@ -1,7 +1,5 @@ import unittest -import datetime - from odml import Property, Section, Document, DType from odml.property import BaseProperty from odml.section import BaseSection @@ -9,9 +7,6 @@ class TestProperty(unittest.TestCase): - def setUp(self): - pass - def test_simple_attributes(self): p_name = "propertyName" p_origin = "from over there" @@ -70,34 +65,34 @@ def test_simple_attributes(self): self.assertIsNone(prop.dependency_value) def test_value(self): - p = Property("property", 100) - self.assertEqual(p.values[0], 100) - self.assertIsInstance(p.values, list) + prop = Property("property", 100) + self.assertEqual(prop.values[0], 100) + self.assertIsInstance(prop.values, list) - p.values = None - self.assertEqual(len(p), 0) + prop.values = None + self.assertEqual(len(prop), 0) - p.values = [1, 2, 3] - p.values = "" - self.assertEqual(len(p), 0) + prop.values = [1, 2, 3] + prop.values = "" + self.assertEqual(len(prop), 0) - p.values = [1, 2, 3] - p.values = [] - self.assertEqual(len(p), 0) + prop.values = [1, 2, 3] + prop.values = [] + self.assertEqual(len(prop), 0) - p.values = [1, 2, 3] - p.values = () - self.assertEqual(len(p), 0) + prop.values = [1, 2, 3] + prop.values = () + self.assertEqual(len(prop), 0) - p.values.append(5) - self.assertEqual(len(p.values), 0) + prop.values.append(5) + self.assertEqual(len(prop.values), 0) - p2 = Property("test", {"name": "Marie", "name": "Johanna"}) - self.assertEqual(len(p2), 1) + prop2 = Property("test", {"name": "Marie"}) + self.assertEqual(len(prop2), 1) # Test tuple dtype value. - t = Property(name="Location", value='(39.12; 67.19)', dtype='2-tuple') - tuple_value = t.values[0] # As the formed tuple is a list of list + prop_tuple = Property(name="Location", value='(39.12; 67.19)', dtype='2-tuple') + tuple_value = prop_tuple.values[0] # As the formed tuple is a list of list self.assertEqual(tuple_value[0], '39.12') self.assertEqual(tuple_value[1], '67.19') @@ -105,17 +100,17 @@ def test_value(self): with self.assertRaises(ValueError): _ = Property(name="Public-Key", value='(5689; 1254; 687)', dtype='2-tuple') - p3 = Property('myprop', value=0, dtype=DType.int) - self.assertEqual(p3.value, [0]) - self.assertEqual(p3.values, [0]) + prop3 = Property('myprop', value=0, dtype=DType.int) + self.assertEqual(prop3.value, [0]) + self.assertEqual(prop3.values, [0]) - p4 = Property('myprop', value=0, dtype=DType.boolean) - self.assertEqual(p4.value, [False]) - self.assertEqual(p4.values, [False]) + prop4 = Property('myprop', value=0, dtype=DType.boolean) + self.assertEqual(prop4.value, [False]) + self.assertEqual(prop4.values, [False]) - p5 = Property('myprop', value=0) - self.assertEqual(p5.value, [0]) - self.assertEqual(p5.values, [0]) + prop5 = Property('myprop', value=0) + self.assertEqual(prop5.value, [0]) + self.assertEqual(prop5.values, [0]) with self.assertRaises(ValueError): Property(name="dateprop", dtype=DType.date, value=['20190707']) @@ -129,7 +124,6 @@ def test_value(self): with self.assertRaises(ValueError): Property(name="intprop", dtype=DType.int, value=[2, "Hello!", 4]) - def test_value_append(self): # Test append w/o Property value or dtype prop = Property(name="append") @@ -205,36 +199,38 @@ def test_value_append(self): prop.append("invalid") self.assertEqual(prop.values, [1, 2, 3, 1, 5]) - p5 = Property("test", value="a string") - p5.append("Freude") - self.assertEqual(len(p5), 2) - self.assertRaises(ValueError, p5.append, "[a, b, c]") - - p6 = Property(name="prop", value=["A Abraham", "B Barnes", "C Clark"], dtype=DType.person) - p6.append("D Dickins") - self.assertEqual(len(p6), 4) - self.assertRaises(ValueError, p6.append, 1) - self.assertRaises(ValueError, p6.append, 1.3) - self.assertRaises(ValueError, p6.append, True) - - p7 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"], dtype=DType.url) - p7.append("https://en.wikipedia.org/wiki/Mars") - self.assertEqual(len(p7), 2) - self.assertRaises(ValueError, p7.append, 1) - self.assertRaises(ValueError, p7.append, 1.3) - self.assertRaises(ValueError, p7.append, True) - - p8 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text) - p8.append("Mars is No. 4.") - self.assertEqual(len(p8), 2) - self.assertRaises(ValueError, p8.append, 1) - 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)") + prop5 = Property("test", value="a string") + prop5.append("Freude") + self.assertEqual(len(prop5), 2) + self.assertRaises(ValueError, prop5.append, "[a, b, c]") + + prop6 = Property(name="prop", value=["A Abraham", "B Barnes", "C Clark"], + dtype=DType.person) + prop6.append("D Dickins") + self.assertEqual(len(prop6), 4) + self.assertRaises(ValueError, prop6.append, 1) + self.assertRaises(ValueError, prop6.append, 1.3) + self.assertRaises(ValueError, prop6.append, True) + + prop7 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"], + dtype=DType.url) + prop7.append("https://en.wikipedia.org/wiki/Mars") + self.assertEqual(len(prop7), 2) + self.assertRaises(ValueError, prop7.append, 1) + self.assertRaises(ValueError, prop7.append, 1.3) + self.assertRaises(ValueError, prop7.append, True) + + prop8 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text) + prop8.append("Mars is No. 4.") + self.assertEqual(len(prop8), 2) + self.assertRaises(ValueError, prop8.append, 1) + self.assertRaises(ValueError, prop8.append, 1.3) + self.assertRaises(ValueError, prop8.append, True) + + prop9 = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)") + prop9.append("(7; 8; 9)") + self.assertEqual(len(prop9), 2) + self.assertRaises(ValueError, prop9.append, "(10; 11)") def test_value_extend(self): prop = Property(name="extend") @@ -313,26 +309,28 @@ def test_value_extend(self): with self.assertRaises(ValueError): prop.extend([6, "some text"]) - p1 = Property(name="prop", value=["A Abraham", "B Barnes", "C Clark"], dtype=DType.person) - p1.extend("D Dickins") - self.assertEqual(len(p1), 4) - self.assertRaises(ValueError, p1.extend, 1) - self.assertRaises(ValueError, p1.extend, 1.3) - self.assertRaises(ValueError, p1.extend, True) - - 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.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.extend, 1) - self.assertRaises(ValueError, p3.extend, 1.3) - self.assertRaises(ValueError, p3.extend, True) + prop1 = Property(name="prop", value=["A Abraham", "B Barnes", "C Clark"], + dtype=DType.person) + prop1.extend("D Dickins") + self.assertEqual(len(prop1), 4) + self.assertRaises(ValueError, prop1.extend, 1) + self.assertRaises(ValueError, prop1.extend, 1.3) + self.assertRaises(ValueError, prop1.extend, True) + + prop2 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"], + dtype=DType.url) + prop2.extend("https://en.wikipedia.org/wiki/Mars") + self.assertEqual(len(prop2), 2) + self.assertRaises(ValueError, prop2.extend, 1) + self.assertRaises(ValueError, prop2.extend, 1.3) + self.assertRaises(ValueError, prop2.extend, True) + + prop3 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text) + prop3.extend("Mars is No. 4.") + self.assertEqual(len(prop3), 2) + self.assertRaises(ValueError, prop3.extend, 1) + self.assertRaises(ValueError, prop3.extend, 1.3) + self.assertRaises(ValueError, prop3.extend, True) prop = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)") prop.extend(["(7; 8; 9)", "(10; 11; 12)"]) @@ -341,81 +339,81 @@ def test_value_extend(self): def test_get_set_value(self): values = [1, 2, 3, 4, 5] - p = Property("property", value=values) + prop = Property("property", value=values) - self.assertEqual(len(p), 5) - for s, d in zip(values, p.values): - self.assertEqual(s, d) + self.assertEqual(len(prop), 5) + for lval, pval in zip(values, prop.values): + self.assertEqual(lval, pval) count = 0 - for v in p: + for _ in prop: count += 1 self.assertEqual(count, len(values)) - p[0] = 10 - self.assertEqual(p[0], 10) + prop[0] = 10 + self.assertEqual(prop[0], 10) with self.assertRaises(ValueError): - p[1] = 'stringval' + prop[1] = 'stringval' def test_bool_conversion(self): # Success tests - p = Property(name='received', value=[1, 0, 1, 0, 1]) - assert(p.dtype == 'int') - p.dtype = DType.boolean - assert(p.dtype == 'boolean') - assert(p.values == [True, False, True, False, True]) - - q = Property(name='sent', value=['False', True, 'TRUE', '0', 't', 'F', '1']) - assert(q.dtype == 'string') - q.dtype = DType.boolean - assert(q.dtype == 'boolean') - assert(q.values == [False, True, True, False, True, False, True]) + prop = Property(name='received', value=[1, 0, 1, 0, 1]) + self.assertEqual(prop.dtype, 'int') + prop.dtype = DType.boolean + self.assertEqual(prop.dtype, 'boolean') + self.assertEqual(prop.values, [True, False, True, False, True]) + + prop = Property(name='sent', value=['False', True, 'TRUE', '0', 't', 'F', '1']) + self.assertEqual(prop.dtype, 'string') + prop.dtype = DType.boolean + self.assertEqual(prop.dtype, 'boolean') + self.assertEqual(prop.values, [False, True, True, False, True, False, True]) # Failure tests curr_val = [3, 0, 1, 0, 8] curr_type = 'int' - p = Property(name='received', value=curr_val) - assert(p.dtype == curr_type) + prop = Property(name='received', value=curr_val) + self.assertEqual(prop.dtype, curr_type) with self.assertRaises(ValueError): - p.dtype = DType.boolean - assert(p.dtype == curr_type) - assert(p.values == curr_val) + prop.dtype = DType.boolean + self.assertEqual(prop.dtype, curr_type) + self.assertEqual(prop.values, curr_val) curr_type = 'string' - q = Property(name='sent', value=['False', True, 'TRUE', '0', 't', '12', 'Ft']) - assert(q.dtype == curr_type) + prop = Property(name='sent', value=['False', True, 'TRUE', '0', 't', '12', 'Ft']) + self.assertEqual(prop.dtype, curr_type) with self.assertRaises(ValueError): - q.dtype = DType.boolean - assert(q.dtype == curr_type) + prop.dtype = DType.boolean + self.assertEqual(prop.dtype, curr_type) def test_str_to_int_convert(self): # Success Test - p = Property(name='cats_onboard', value=['3', '0', '1', '0', '8']) - assert(p.dtype == 'string') - p.dtype = DType.int - assert(p.dtype == 'int') - assert(p.values == [3, 0, 1, 0, 8]) + prop = Property(name='cats_onboard', value=['3', '0', '1', '0', '8']) + self.assertEqual(prop.dtype, 'string') + prop.dtype = DType.int + self.assertEqual(prop.dtype, 'int') + self.assertEqual(prop.values, [3, 0, 1, 0, 8]) # Failure Test - p = Property(name='dogs_onboard', value=['7', '20', '1 Dog', 'Seven']) - assert(p.dtype == 'string') + prop = Property(name='dogs_onboard', value=['7', '20', '1 Dog', 'Seven']) + self.assertEqual(prop.dtype, 'string') with self.assertRaises(ValueError): - p.dtype = DType.int + prop.dtype = DType.int - assert(p.dtype == 'string') - assert(p.values == ['7', '20', '1 Dog', 'Seven']) + self.assertEqual(prop.dtype, 'string') + self.assertEqual(prop.values, ['7', '20', '1 Dog', 'Seven']) def test_name(self): # Test id is used when name is not provided - p = Property() - self.assertIsNotNone(p.name) - self.assertEqual(p.name, p.id) + prop = Property() + self.assertIsNotNone(prop.name) + self.assertEqual(prop.name, prop.id) # Test name is properly set on init name = "rumpelstilzchen" - p = Property(name) - self.assertEqual(p.name, name) + prop = Property(name) + self.assertEqual(prop.name, name) # Test name can be properly set on single and connected Properties prop = Property() @@ -441,22 +439,22 @@ def test_name(self): self.assertEqual(prop_b.name, "prop") def test_parent(self): - p = Property("property_section", parent=Section("S")) - self.assertIsInstance(p.parent, BaseSection) - self.assertEqual(len(p.parent._props), 1) + prop = Property("property_section", parent=Section("S")) + self.assertIsInstance(prop.parent, BaseSection) + self.assertEqual(len(prop.parent.props), 1) """ Test if child is removed from _props of a parent after assigning a new parent to the child """ - prop_parent = p.parent - p.parent = Section("S1") - self.assertEqual(len(prop_parent._props), 0) - self.assertIsInstance(p.parent, BaseSection) - self.assertIsInstance(p.parent._props[0], BaseProperty) + prop_parent = prop.parent + prop.parent = Section("S1") + self.assertEqual(len(prop_parent.props), 0) + self.assertIsInstance(prop.parent, BaseSection) + self.assertIsInstance(prop.parent.props[0], BaseProperty) - prop_parent = p.parent - p.parent = None - self.assertIsNone(p.parent) - self.assertEqual(len(prop_parent._props), 0) + prop_parent = prop.parent + prop.parent = None + self.assertIsNone(prop.parent) + self.assertEqual(len(prop_parent.props), 0) with self.assertRaises(ValueError): Property("property_prop", parent=Property("P")) @@ -512,18 +510,18 @@ def test_get_path(self): self.assertEqual("/%s:%s" % (sec.name, prop.name), prop.get_path()) def test_id(self): - p = Property(name="P") - self.assertIsNotNone(p.id) + prop = Property(name="P") + self.assertIsNotNone(prop.id) - p = Property("P", oid="79b613eb-a256-46bf-84f6-207df465b8f7") - self.assertEqual(p.id, "79b613eb-a256-46bf-84f6-207df465b8f7") + prop = Property("P", oid="79b613eb-a256-46bf-84f6-207df465b8f7") + self.assertEqual(prop.id, "79b613eb-a256-46bf-84f6-207df465b8f7") - p = Property("P", oid="id") - self.assertNotEqual(p.id, "id") + prop = Property("P", oid="id") + self.assertNotEqual(prop.id, "id") # Make sure id cannot be reset programmatically. with self.assertRaises(AttributeError): - p.id = "someId" + prop.id = "someId" def test_new_id(self): prop = Property(name="prop") @@ -631,9 +629,11 @@ def test_merge_check(self): destination.merge_check(source, False) def test_merge(self): - p_dst = Property("p1", value=[1, 2, 3], unit="Hz", definition="Freude\t schoener\nGoetterfunken\n", + p_dst = Property("p1", value=[1, 2, 3], unit="Hz", + definition="Freude\t schoener\nGoetterfunken\n", reference="portal.g-node.org", uncertainty=0.0, value_origin="file") - p_src = Property("p2", value=[2, 4, 6], unit="Hz", definition="FREUDE schoener GOETTERfunken") + p_src = Property("p2", value=[2, 4, 6], unit="Hz", + definition="FREUDE schoener GOETTERfunken") test_p = p_dst.clone() test_p.merge(p_src) @@ -760,39 +760,28 @@ def test_comparison(self): def test_export_leaf(self): doc = Document() - first = doc.create_section("first") - second = first.create_section("second") - first.create_section("third") - - name = "prop1" - values = [1.3] - first.create_property(name, value=values) - - name = "prop2" - values = ["words"] - second.create_property(name, value=values) - name = "prop3" - values = ["a", "b"] - second.create_property(name, value=values) + sec_a_name = "first" + sec_b_name = "second" + first = doc.create_section(sec_a_name) + second = first.create_section(sec_b_name) + _ = first.create_section("third") - name = "prop4" - values = [3] - second.create_property(name, value=values) + prop_aa = first.create_property("prop1", value=[1.3]) + _ = first.create_property("prop5", value=["abc"]) + prop_ba = second.create_property("prop2", value=["words"]) + _ = second.create_property("prop3", value=["a", "b"]) + _ = second.create_property("prop4", value=[3]) - name = "prop5" - values = ["abc"] - first.create_property(name, value=values) + export_doc = prop_aa.export_leaf() + self.assertEqual(len(export_doc[sec_a_name].properties), 2) + self.assertEqual(len(export_doc[sec_a_name].sections), 0) - ex1 = first.properties["prop1"].export_leaf() - self.assertEqual(len(ex1['first'].properties), 1) - self.assertEqual(len(ex1['first'].sections), 0) - - ex2 = second.properties["prop2"].export_leaf() - self.assertEqual(len(ex2.sections), 1) - self.assertEqual(len(ex2['first'].properties), 2) - self.assertEqual(len(ex2['first'].sections), 1) - self.assertEqual(len(ex2['first']['second'].properties), 1) + export_doc = prop_ba.export_leaf() + self.assertEqual(len(export_doc.sections), 1) + self.assertEqual(len(export_doc[sec_a_name].properties), 2) + self.assertEqual(len(export_doc[sec_a_name].sections), 1) + self.assertEqual(len(export_doc[sec_a_name][sec_b_name].properties), 3) def test_values_cardinality(self): doc = Document() @@ -898,10 +887,3 @@ def test_set_values_cardinality(self): self.assertIsNotNone(prop.val_cardinality) prop.set_values_cardinality(min_val=None, max_val=None) self.assertIsNone(prop.val_cardinality) - - -if __name__ == "__main__": - print("TestProperty") - tp = TestProperty() - tp.test_value() - tp.test_merge() diff --git a/test/test_rdf_reader.py b/test/test_rdf_reader.py index 2f405d27..a4058cd6 100644 --- a/test/test_rdf_reader.py +++ b/test/test_rdf_reader.py @@ -2,13 +2,13 @@ import unittest from rdflib import Literal -import odml.format as format from odml import Property, Section, Document +from odml.format import Format from odml.tools.rdf_converter import RDFWriter, RDFReader from odml.tools.parser_utils import ParserException -odmlns = format.Format.namespace() +ODMLNS = Format.namespace() class TestRDFReader(unittest.TestCase): @@ -25,23 +25,23 @@ def test_rdf_formats(self): """ Test if document gets correctly converted to odml for turtle, xml and n3. """ - w = RDFWriter(self.doc).get_rdf_str() - r = RDFReader().from_string(w, "turtle") - self.assertEqual(len(r[0].sections), 1) - self.assertEqual(len(r[0].sections[0].sections), 1) - self.assertEqual(len(r[0].sections[0].properties), 1) - - w = RDFWriter(self.doc).get_rdf_str("xml") - r = RDFReader().from_string(w, "xml") - self.assertEqual(len(r[0].sections), 1) - self.assertEqual(len(r[0].sections[0].sections), 1) - self.assertEqual(len(r[0].sections[0].properties), 1) - - w = RDFWriter(self.doc).get_rdf_str("n3") - r = RDFReader().from_string(w, "n3") - self.assertEqual(len(r[0].sections), 1) - self.assertEqual(len(r[0].sections[0].sections), 1) - self.assertEqual(len(r[0].sections[0].properties), 1) + rdf_writer = RDFWriter(self.doc).get_rdf_str() + rdf_reader = RDFReader().from_string(rdf_writer, "turtle") + self.assertEqual(len(rdf_reader[0].sections), 1) + self.assertEqual(len(rdf_reader[0].sections[0].sections), 1) + self.assertEqual(len(rdf_reader[0].sections[0].properties), 1) + + rdf_writer = RDFWriter(self.doc).get_rdf_str("xml") + rdf_reader = RDFReader().from_string(rdf_writer, "xml") + self.assertEqual(len(rdf_reader[0].sections), 1) + self.assertEqual(len(rdf_reader[0].sections[0].sections), 1) + self.assertEqual(len(rdf_reader[0].sections[0].properties), 1) + + rdf_writer = RDFWriter(self.doc).get_rdf_str("n3") + rdf_reader = RDFReader().from_string(rdf_writer, "n3") + self.assertEqual(len(rdf_reader[0].sections), 1) + self.assertEqual(len(rdf_reader[0].sections[0].sections), 1) + self.assertEqual(len(rdf_reader[0].sections[0].properties), 1) def test_doc(self): """ @@ -52,12 +52,12 @@ def test_doc(self): doc.version = 42 doc.date = datetime.date(1979, 10, 12) - w = RDFWriter(doc).get_rdf_str() - r = RDFReader().from_string(w, "turtle") + rdf_writer = RDFWriter(doc).get_rdf_str() + rdf_reader = RDFReader().from_string(rdf_writer, "turtle") - self.assertEqual(r[0].author, "D. N. Adams") - self.assertEqual(r[0].version, "42") - self.assertEqual(r[0].date, datetime.date(1979, 10, 12)) + self.assertEqual(rdf_reader[0].author, "D. N. Adams") + self.assertEqual(rdf_reader[0].version, "42") + self.assertEqual(rdf_reader[0].date, datetime.date(1979, 10, 12)) def test_section(self): """ @@ -68,16 +68,16 @@ def test_section(self): reference="The Journal") Section(name="sec2", type="test", parent=sec1) - w = RDFWriter(doc).get_rdf_str() - r = RDFReader().from_string(w, "turtle") + rdf_writer = RDFWriter(doc).get_rdf_str() + rdf_reader = RDFReader().from_string(rdf_writer, "turtle") - self.assertEqual(r[0].sections[0].name, "sec1") - self.assertEqual(r[0].sections[0].type, "test") - self.assertEqual(r[0].sections[0].id, sec1.id) - self.assertEqual(r[0].sections[0].definition, "Interesting stuff.") - self.assertEqual(r[0].sections[0].reference, "The Journal") - self.assertEqual(r[0].sections[0].parent, r[0]) - self.assertEqual(len(r[0].sections[0].sections), 1) + self.assertEqual(rdf_reader[0].sections[0].name, "sec1") + self.assertEqual(rdf_reader[0].sections[0].type, "test") + self.assertEqual(rdf_reader[0].sections[0].id, sec1.id) + self.assertEqual(rdf_reader[0].sections[0].definition, "Interesting stuff.") + self.assertEqual(rdf_reader[0].sections[0].reference, "The Journal") + self.assertEqual(rdf_reader[0].sections[0].parent, rdf_reader[0]) + self.assertEqual(len(rdf_reader[0].sections[0].sections), 1) def test_property(self): """ @@ -89,15 +89,15 @@ def test_property(self): values=[1, 3.4, 67.8, -12], unit="meter", uncertainty=0.8, value_origin="force", reference="Experiment 1") - w = RDFWriter(doc).get_rdf_str() - r = RDFReader().from_string(w, "turtle") + rdf_writer = RDFWriter(doc).get_rdf_str() + rdf_reader = RDFReader().from_string(rdf_writer, "turtle") - prop = r[0].sections[0].properties["numbers"] + prop = rdf_reader[0].sections[0].properties["numbers"] self.assertEqual(prop.name, "numbers") self.assertEqual(prop.dtype, "float") self.assertEqual(prop.id, prop2.id) - self.assertEqual(prop.parent, r[0].sections[0]) + self.assertEqual(prop.parent, rdf_reader[0].sections[0]) self.assertEqual(len(prop.values), 4) self.assertEqual(prop.values, [1, 3.4, 67.8, -12]) self.assertEqual(prop.definition, "any number") @@ -110,12 +110,12 @@ def test_mandatory_attrs_section(self): """ Test if ParserError is thrown if mandatory attributes are missing for section. """ - w = RDFWriter([self.doc]) - w.convert_to_rdf() - for rdf_sec in w.graph.subjects(predicate=odmlns.hasName, object=Literal("sec1")): - w.graph.remove((rdf_sec, odmlns.hasName, Literal("sec1"))) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() + for rdf_sec in rdf_writer.graph.subjects(predicate=ODMLNS.hasName, object=Literal("sec1")): + rdf_writer.graph.remove((rdf_sec, ODMLNS.hasName, Literal("sec1"))) - new_graph = w.graph.serialize(format="turtle").decode("utf-8") + new_graph = rdf_writer.graph.serialize(format="turtle").decode("utf-8") with self.assertRaises(ParserException): RDFReader().from_string(new_graph, "turtle") @@ -124,12 +124,12 @@ def test_mandatory_attrs_property(self): """ Test if ParserError is thrown if mandatory attributes are missing for section. """ - w = RDFWriter([self.doc]) - w.convert_to_rdf() - for rdf_sec in w.graph.subjects(predicate=odmlns.hasName, object=Literal("prop1")): - w.graph.remove((rdf_sec, odmlns.hasName, Literal("prop1"))) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() + for rdf_sec in rdf_writer.graph.subjects(predicate=ODMLNS.hasName, object=Literal("prop1")): + rdf_writer.graph.remove((rdf_sec, ODMLNS.hasName, Literal("prop1"))) - new_graph = w.graph.serialize(format="turtle").decode("utf-8") + new_graph = rdf_writer.graph.serialize(format="turtle").decode("utf-8") with self.assertRaises(ParserException): RDFReader().from_string(new_graph, "turtle") diff --git a/test/test_rdf_writer.py b/test/test_rdf_writer.py index 54040b93..e3a4a23a 100644 --- a/test/test_rdf_writer.py +++ b/test/test_rdf_writer.py @@ -1,19 +1,21 @@ import datetime import os import unittest -from os.path import dirname, abspath import yaml + from rdflib import URIRef, Literal from rdflib.namespace import XSD, RDF import odml -import odml.format as format + +from odml.format import Format from odml.tools.rdf_converter import RDFWriter -from test.test_samplefile import SampleFileCreator -from test.test_samplefile import parse -odmlns = format.Format.namespace() +from .test_samplefile import SampleFileCreator +from .test_samplefile import parse + +ODMLNS = Format.namespace() class TestRDFWriter(unittest.TestCase): @@ -25,44 +27,68 @@ def setUp(self): self.doc1 = doc1 def test_convert_to_rdf(self): - w = RDFWriter([self.doc, self.doc1]) - w.convert_to_rdf() - doc_subjects = w.graph.subjects(predicate=RDF.type, object=URIRef(odmlns.Document)) - self.assertEqual(len(list(doc_subjects)), 2) + rdf_writer = RDFWriter([self.doc, self.doc1]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subjects(predicate=RDF.type, + object=URIRef(ODMLNS.Document)) + self.assertEqual(len(list(check)), 2) def test_adding_doc_to_the_hub(self): - w = RDFWriter([self.doc]) - w.convert_to_rdf() - hub_hasDocument = w.graph.objects(subject=w.hub_root, predicate=odmlns.hasDocument) - self.assertEqual(len(list(hub_hasDocument)), 1) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.objects(subject=rdf_writer.hub_root, + predicate=ODMLNS.hasDocument) + self.assertEqual(len(list(check)), 1) def test_adding_repository(self): - w = RDFWriter([self.doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.objects(subject=w.hub_root, predicate=odmlns.hasTerminology))), 0) - self.assertEqual(len(list(w.graph.objects(subject=URIRef(odmlns + w.docs[0].id), predicate=odmlns.hasTerminology))), 0) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.objects(subject=rdf_writer.hub_root, + predicate=ODMLNS.hasTerminology) + self.assertEqual(len(list(check)), 0) + + check = rdf_writer.graph.objects(subject=URIRef(ODMLNS + rdf_writer.docs[0].id), + predicate=ODMLNS.hasTerminology) + self.assertEqual(len(list(check)), 0) url = "terminology_url" self.doc.repository = url - w = RDFWriter([self.doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.type, object=URIRef(url)))), 1) - self.assertEqual(len(list(w.graph.objects(subject=w.hub_root, predicate=odmlns.hasTerminology))), 1) - self.assertEqual(len(list(w.graph.objects(subject=URIRef(odmlns + w.docs[0].id), predicate=odmlns.hasTerminology))), 1) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subjects(predicate=RDF.type, object=URIRef(url)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.objects(subject=rdf_writer.hub_root, + predicate=ODMLNS.hasTerminology) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.objects(subject=URIRef(ODMLNS + rdf_writer.docs[0].id), + predicate=ODMLNS.hasTerminology) + self.assertEqual(len(list(check)), 1) def test_adding_sections(self): doc = odml.Document() - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=odmlns.hasSection))), 0) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subject_objects(predicate=ODMLNS.hasSection) + self.assertEqual(len(list(check)), 0) - w = RDFWriter([self.doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=odmlns.hasSection))), 9) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() - w = RDFWriter([self.doc, self.doc1]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=odmlns.hasSection))), 18) + check = rdf_writer.graph.subject_objects(predicate=ODMLNS.hasSection) + self.assertEqual(len(list(check)), 9) + + rdf_writer = RDFWriter([self.doc, self.doc1]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subject_objects(predicate=ODMLNS.hasSection) + self.assertEqual(len(list(check)), 18) def test_adding_properties(self): doc = parse(""" @@ -70,52 +96,73 @@ def test_adding_properties(self): - s11[t1] s2[t2] """) - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=odmlns.hasProperty))), 0) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subject_objects(predicate=ODMLNS.hasProperty) + self.assertEqual(len(list(check)), 0) - w = RDFWriter([self.doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=odmlns.hasProperty))), 12) + rdf_writer = RDFWriter([self.doc]) + rdf_writer.convert_to_rdf() - w = RDFWriter([self.doc, self.doc1]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=odmlns.hasProperty))), 24) + check = rdf_writer.graph.subject_objects(predicate=ODMLNS.hasProperty) + self.assertEqual(len(list(check)), 12) + + rdf_writer = RDFWriter([self.doc, self.doc1]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subject_objects(predicate=ODMLNS.hasProperty) + self.assertEqual(len(list(check)), 24) def test_adding_values(self): doc = parse(""" s1[t1] """) - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=RDF.li))), 0) - self.assertEqual(len(list( - w.graph.subject_objects(predicate=URIRef("%s_1" % str(RDF))))), 0) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subject_objects(predicate=RDF.li) + self.assertEqual(len(list(check)), 0) + + check = rdf_writer.graph.subject_objects(predicate=URIRef("%s_1" % str(RDF))) + self.assertEqual(len(list(check)), 0) doc = parse(""" s1[t1] - p1 """) - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.li, - object=Literal("val")))), 0) - self.assertEqual(len(list(w.graph.subjects(predicate=URIRef("%s_1" % str(RDF)), - object=Literal("val")))), 1) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subjects(predicate=RDF.li, object=Literal("val")) + self.assertEqual(len(list(check)), 0) + + check = rdf_writer.graph.subjects(predicate=URIRef("%s_1" % str(RDF)), + object=Literal("val")) + self.assertEqual(len(list(check)), 1) doc.sections[0].properties[0].append("val2") - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subject_objects(predicate=RDF.li))), 0) - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.li, object=Literal("val")))), 0) - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.li, object=Literal("val2")))), 0) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subject_objects(predicate=RDF.li) + self.assertEqual(len(list(check)), 0) + + check = rdf_writer.graph.subjects(predicate=RDF.li, object=Literal("val")) + self.assertEqual(len(list(check)), 0) - self.assertEqual(len(list(w.graph.subjects(predicate=URIRef("%s_1" % str(RDF)), - object=Literal("val")))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=URIRef("%s_2" % str(RDF)), - object=Literal("val2")))), 1) + check = rdf_writer.graph.subjects(predicate=RDF.li, object=Literal("val2")) + self.assertEqual(len(list(check)), 0) + + check = rdf_writer.graph.subjects(predicate=URIRef("%s_1" % str(RDF)), + object=Literal("val")) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=URIRef("%s_2" % str(RDF)), + object=Literal("val2")) + self.assertEqual(len(list(check)), 1) doc = parse(""" s1[t1] @@ -125,25 +172,35 @@ def test_adding_values(self): - p2 """) - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.li, object=Literal("val")))), 0) - self.assertEqual(len(list(w.graph.subjects(predicate=URIRef("%s_1" % str(RDF)), - object=Literal("val")))), 3) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subjects(predicate=RDF.li, object=Literal("val")) + self.assertEqual(len(list(check)), 0) + + check = rdf_writer.graph.subjects(predicate=URIRef("%s_1" % str(RDF)), + object=Literal("val")) + self.assertEqual(len(list(check)), 3) def test_section_subclass(self): - p = os.path.join(odml.__path__[0], 'resources', 'section_subclasses.yaml') - with open(p, "r") as f: - subclass = yaml.safe_load(f) + file_path = os.path.join(odml.__path__[0], 'resources', 'section_subclasses.yaml') + with open(file_path, "r") as subclass_file: + subclass = yaml.safe_load(subclass_file) doc = odml.Document() subclass_key = next(iter(subclass)) - s = odml.Section("S", type=subclass_key) - doc.append(s) - w = RDFWriter(doc) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.type, object=URIRef(odmlns[subclass[subclass_key]])))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=RDF.type, object=URIRef(odmlns.Section)))), 0) + sec = odml.Section("S", type=subclass_key) + doc.append(sec) + + rdf_writer = RDFWriter(doc) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subjects(predicate=RDF.type, + object=URIRef(ODMLNS[subclass[subclass_key]])) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=RDF.type, object=URIRef(ODMLNS.Section)) + self.assertEqual(len(list(check)), 0) def test_adding_other_entities_properties(self): doc = parse(""" @@ -177,27 +234,57 @@ def test_adding_other_entities_properties(self): doc.sections[0].properties[0].value_origin = p_value_origin doc.sections[0].properties[0].reference = p_ref - w = RDFWriter([doc]) - w.convert_to_rdf() - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasDocVersion, object=Literal(version)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasDate, object=Literal(date, datatype=XSD.date)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasAuthor, object=Literal(author)))), 1) - - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasName, object=Literal("s1")))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasType, object=Literal("t1")))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasDefinition, object=Literal(s_def)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasReference, object=Literal(s_ref)))), 1) - - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasName, object=Literal(p_name)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasUnit, object=Literal(p_unit)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasDefinition, object=Literal(p_def)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasUncertainty, object=Literal(p_uncertainty)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasDtype, object=Literal(p_dtype)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasValueOrigin, object=Literal(p_value_origin)))), 1) - self.assertEqual(len(list(w.graph.subjects(predicate=odmlns.hasReference, object=Literal(p_ref)))), 1) + rdf_writer = RDFWriter([doc]) + rdf_writer.convert_to_rdf() + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasDocVersion, object=Literal(version)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasDate, + object=Literal(date, datatype=XSD.date)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasAuthor, object=Literal(author)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasName, object=Literal("s1")) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasType, object=Literal("t1")) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasDefinition, object=Literal(s_def)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasReference, object=Literal(s_ref)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasName, object=Literal(p_name)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasUnit, object=Literal(p_unit)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasDefinition, object=Literal(p_def)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasUncertainty, + object=Literal(p_uncertainty)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasDtype, object=Literal(p_dtype)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasValueOrigin, + object=Literal(p_value_origin)) + self.assertEqual(len(list(check)), 1) + + check = rdf_writer.graph.subjects(predicate=ODMLNS.hasReference, object=Literal(p_ref)) + self.assertEqual(len(list(check)), 1) def test_get_rdf_string(self): - w = RDFWriter([self.doc1]) - w.get_rdf_str() + rdf_writer = RDFWriter([self.doc1]) + rdf_writer.get_rdf_str() + with self.assertRaises(ValueError): - w.get_rdf_str("abc") + rdf_writer.get_rdf_str("abc") diff --git a/test/test_samplefile.py b/test/test_samplefile.py index ffa95133..7fb07313 100644 --- a/test/test_samplefile.py +++ b/test/test_samplefile.py @@ -1,14 +1,18 @@ -import odml - -import unittest import os -import sys import re +import sys import tempfile +import unittest + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +import odml from odml.info import FORMAT_VERSION from odml.tools import xmlparser -from odml.tools import dumper try: unicode = unicode @@ -38,16 +42,17 @@ def parse(data): - s21[t2] linked to /s1/s2 """ lines = data.strip(" ").strip("\n").split("\n") - offset = len(re.compile('(\s*)').match(lines[0]).group()) + offset = len(re.compile(r'(\s*)').match(lines[0]).group()) pat = re.compile(r'(?P\w+)(\[(?P\w+)\])?(\s+mapping \[(?P' - '[\w:]+)\])?(\s+linked to (?P[\w/]+))?') + r'[\w:]+)\])?(\s+linked to (?P[\w/]+))?') + parents = [odml.Document(), None] for line in lines: line = line[offset:] while len(parents) > 1: - parpref = (len(parents) - 2) * 2 - if line.startswith(" " * parpref): - line = line[parpref:] + parp_ref = (len(parents) - 2) * 2 + if line.startswith(" " * parp_ref): + line = line[parp_ref:] break parents.pop() @@ -57,54 +62,59 @@ def parse(data): parents.pop() try: - m = pat.match(line).groupdict() + match_line = pat.match(line).groupdict() except: print("error parsing", repr(line)) raise - if m['type'] is None: - obj = odml.Property(name=m['name'], value="[val]") + + if match_line['type'] is None: + obj = odml.Property(name=match_line['name'], value="[val]") else: - obj = odml.Section(name=m['name'], type=m['type']) - if m['dst'] is not None: - obj.mapping = 'map#%s' % m['dst'] - if m['link'] is not None: - obj._link = m['link'] + obj = odml.Section(name=match_line['name'], type=match_line['type']) + + if match_line['dst'] is not None: + obj.mapping = 'map#%s' % match_line['dst'] + + if match_line['link'] is not None: + obj._link = match_line['link'] + parents[-1].append(obj) parents.append(obj) + return parents[0] class SampleFileCreator: - def create_document(self): doc = odml.Document() for i in range(3): doc.append(self.create_section("sec %d" % i)) + return doc def create_section(self, name, depth=0): - s = odml.Section(name=name, type=name.replace("sec", "type")) + sec = odml.Section(name=name, type=name.replace("sec", "type")) if depth < 1: for i in range(2): - s.append(self.create_section("%s,%d" % - (name, i), depth=depth + 1)) + sec.append(self.create_section("%s,%d" % (name, i), depth=depth + 1)) if name.endswith("1"): for i in range(3): - s.append(self.create_property("%s:%d" % (name, i))) + sec.append(self.create_property("%s:%d" % (name, i))) - return s + return sec - def create_property(self, name): + @staticmethod + def create_property(name): return odml.Property(name=name.replace("sec", "prop"), value=name.replace("sec", "val")) class SampleFileCreatorTest(unittest.TestCase): - def test_samplefile(self): - doc = SampleFileCreator().create_document() - # dumper.dump_doc(doc) + @staticmethod + def test_sample_file(): + _ = SampleFileCreator().create_document() class SampleFileOperationTest(unittest.TestCase): @@ -144,35 +154,27 @@ def test_xml_writer_version(self): val = unicode(xmlparser.XMLWriter(doc)) else: val = str(xmlparser.XMLWriter(doc)) + self.assertIn('version="%s"' % FORMAT_VERSION, val) doc = xmlparser.XMLReader().from_string(val) + # This test is switched off until the XML versioning support is implemented # self.assertEqual(doc._xml_version, FORMAT_VERSION) def test_save(self): + base_path = tempfile.gettempdir() for module in [xmlparser.XMLWriter]: + path = os.path.join(base_path, "temp.odml") doc = module(self.doc) - import tempfile - - path = tempfile.gettempdir() - path = os.path.join(path, "temp.odml") doc.write_file(path) - os.unlink(path) + os.remove(path) def test_restore(self): - try: - from StringIO import StringIO - except ImportError: - from io import StringIO modules = [(xmlparser.XMLWriter, xmlparser.XMLReader)] for Writer, Reader in modules: - doc = Writer(self.doc) - if sys.version_info < (3, 0): - doc = StringIO(unicode(doc)) - else: - doc = StringIO(str(doc)) + doc = StringIO(unicode(doc)) doc = Reader().from_file(doc) self.assertEqual(doc, self.doc) @@ -191,48 +193,50 @@ def test_restore(self): class AttributeTest(unittest.TestCase): def test_value_int(self): - p = odml.Property("test", 1, dtype="int") - self.assertEqual(p.values[0], 1) + prop = odml.Property("test", 1, dtype="int") + self.assertEqual(prop.values[0], 1) def test_conversion_int_to_float(self): - p = odml.Property("test", "1", dtype="int") - self.assertEqual(p.dtype, "int") - self.assertIsInstance(p.values[0], int) - p.dtype = "float" # change dtype - self.assertEqual(p.dtype, "float") - self.assertEqual(p.values[0], 1.0) + prop = odml.Property("test", "1", dtype="int") + self.assertEqual(prop.dtype, "int") + self.assertIsInstance(prop.values[0], int) + + # change dtype + prop.dtype = "float" + self.assertEqual(prop.dtype, "float") + self.assertEqual(prop.values[0], 1.0) def test_conversion_float_to_int(self): - p = odml.Property("test", "1.5", dtype="float") - self.assertEqual(p.dtype, "float") - p.dtype = "int" - self.assertEqual(p.dtype, "int") - self.assertEqual(p.values[0], 1) + prop = odml.Property("test", "1.5", dtype="float") + self.assertEqual(prop.dtype, "float") + prop.dtype = "int" + self.assertEqual(prop.dtype, "int") + self.assertEqual(prop.values[0], 1) def test_value_float(self): - p = odml.Property("test", value="1.5", dtype="float") - self.assertEqual(p.values[0], 1.5) + prop = odml.Property("test", value="1.5", dtype="float") + self.assertEqual(prop.values[0], 1.5) class CopyTest(unittest.TestCase): def setUp(self): - self.p = odml.Property(name="test", value=1) + self.prop = odml.Property(name="test", value=1) def test_dependence(self): - a = self.p - b = self.p - self.assertEqual(a, b) - a.values = 5 - self.assertEqual(a, b) - self.assertEqual(a.values, b.values) + prop1 = self.prop + prop2 = self.prop + self.assertEqual(prop1, prop2) + prop1.values = 5 + self.assertEqual(prop1, prop2) + self.assertEqual(prop1.values, prop2.values) def test_independence(self): - a = self.p.clone() - b = self.p.clone() - self.assertEqual(a, b) - a.values = 5 - self.assertNotEqual(a, b) + prop1 = self.prop.clone() + prop2 = self.prop.clone() + self.assertEqual(prop1, prop2) + prop1.values = 5 + self.assertNotEqual(prop1, prop2) # self.assertUn @@ -242,7 +246,7 @@ def setUp(self): self.doc = SampleFileCreator().create_document() def test_paths(self): - sec = odml.Section("bar") + sec = odml.Section("sec") self.assertEqual(sec._get_relative_path("/a", "/b"), "/b") self.assertEqual(sec._get_relative_path("/a", "/a/b"), "b") self.assertEqual(sec._get_relative_path("/a/b", "/a/c"), "../c") @@ -297,9 +301,7 @@ def test_reorder_first(self): self.assertEqual(self.doc.sections[2].name, "sec 1") def test_get_section_by_path(self): - sec0 = self.doc.sections[0] sec1 = self.doc.sections[1] - sec01 = sec0.sections[1] sec10 = sec1.sections[0] sec11 = sec1.sections[1] @@ -321,18 +323,17 @@ def test_get_section_by_path(self): self.assertEqual(current, sec11) # test wrong parent - wrongpath = "../" + sec10.get_relative_path(sec11) - self.assertRaises(ValueError, sec10.get_section_by_path, wrongpath) + wrong_path = "../" + sec10.get_relative_path(sec11) + self.assertRaises(ValueError, sec10.get_section_by_path, wrong_path) # test wrong child - wrongpath = sec1.get_relative_path(sec10) + "/foo" - self.assertRaises(ValueError, sec1.get_section_by_path, wrongpath) + wrong_path = sec1.get_relative_path(sec10) + "/sec" + self.assertRaises(ValueError, sec1.get_section_by_path, wrong_path) # test absolute path with no document - newsec = SampleFileCreator().create_section("foo", 0) - path = newsec.sections[0].get_path() - self.assertRaises(ValueError, - newsec.sections[1].get_section_by_path, path) + new_sec = SampleFileCreator().create_section("sec", 0) + path = new_sec.sections[0].get_path() + self.assertRaises(ValueError, new_sec.sections[1].get_section_by_path, path) # test path with property is invalid path = sec11.properties[0].get_path() @@ -355,17 +356,17 @@ def test_get_property_by_path(self): self.assertEqual(current, prop) # test relative path from section - manualpath = "../%s/%s:%s" % (sec1.name, sec11.name, prop.name) - current = sec0.get_property_by_path(manualpath) + manual_path = "../%s/%s:%s" % (sec1.name, sec11.name, prop.name) + current = sec0.get_property_by_path(manual_path) self.assertEqual(current, prop) # test non-existing property - wrongpath = sec10.get_relative_path(sec11) + ":foo" - self.assertRaises(ValueError, sec1.get_property_by_path, wrongpath) + wrong_path = sec10.get_relative_path(sec11) + ":foo" + self.assertRaises(ValueError, sec1.get_property_by_path, wrong_path) # test path with section is invalid - wrongpath = sec11.get_path() - self.assertRaises(ValueError, sec1.get_property_by_path, wrongpath) + wrong_path = sec11.get_path() + self.assertRaises(ValueError, sec1.get_property_by_path, wrong_path) def test_save_version(self): tmp_file = os.path.join(tempfile.gettempdir(), "example.odml") diff --git a/test/test_section.py b/test/test_section.py index ba5f0a50..fe149d73 100644 --- a/test/test_section.py +++ b/test/test_section.py @@ -41,18 +41,18 @@ def test_simple_attributes(self): def test_name(self): # Test id is used when name is not provided - s = Section() - self.assertIsNotNone(s.name) - self.assertEqual(s.name, s.id) + sec = Section() + self.assertIsNotNone(sec.name) + self.assertEqual(sec.name, sec.id) # Test name is properly set on init name = "rumpelstilzchen" - s = Section(name) - self.assertEqual(s.name, name) + sec = Section(name) + self.assertEqual(sec.name, name) name = "rumpelstilzchen" - s = Section(name=name) - self.assertEqual(s.name, name) + sec = Section(name=name) + self.assertEqual(sec.name, name) # Test name can be properly set on single and connected Sections sec = Section() @@ -78,41 +78,41 @@ def test_name(self): # Test section name set will fail on existing same name document sibling doc = Document() - sec_a = Section(name="a", parent=doc) + _ = Section(name="a", parent=doc) sec_b = Section(name="b", parent=doc) with self.assertRaises(KeyError): sec_b.name = "a" def test_parent(self): - s = Section("Section") - self.assertIsNone(s.parent) - s.parent = None - self.assertIsNone(s.parent) - s.parent = Document() - self.assertIsInstance(s.parent, BaseDocument) - self.assertIsInstance(s.parent._sections[0], BaseSection) - - """ Test if child is removed from _sections of a parent after assigning - a new parent to the child """ - p = s.parent - s.parent = Section("S") - self.assertEqual(len(p._sections), 0) - - s = Section("section_doc", parent=Document()) - self.assertIsInstance(s.parent, BaseDocument) - self.assertEqual(len(s.parent._sections), 1) - p = s.parent - s.parent = None - self.assertEqual(len(p._sections), 0) - self.assertEqual(s.parent, None) - - s = Section("section_sec", parent=Section("S")) - self.assertIsInstance(s.parent, BaseSection) - self.assertEqual(len(s.parent._sections), 1) - p = s.parent - s.parent = None - self.assertEqual(len(p._sections), 0) - self.assertEqual(s.parent, None) + sec = Section("Section") + self.assertIsNone(sec.parent) + sec.parent = None + self.assertIsNone(sec.parent) + sec.parent = Document() + self.assertIsInstance(sec.parent, BaseDocument) + self.assertIsInstance(sec.parent._sections[0], BaseSection) + + # Test if child is removed from _sections of a parent after + # assigning a new parent to the child. + sec_parent = sec.parent + sec.parent = Section("S") + self.assertEqual(len(sec_parent._sections), 0) + + sec = Section("section_doc", parent=Document()) + self.assertIsInstance(sec.parent, BaseDocument) + self.assertEqual(len(sec.parent._sections), 1) + sec_parent = sec.parent + sec.parent = None + self.assertEqual(len(sec_parent._sections), 0) + self.assertEqual(sec.parent, None) + + sec = Section("section_sec", parent=Section("S")) + self.assertIsInstance(sec.parent, BaseSection) + self.assertEqual(len(sec.parent._sections), 1) + sec_parent = sec.parent + sec.parent = None + self.assertEqual(len(sec_parent._sections), 0) + self.assertEqual(sec.parent, None) with self.assertRaises(ValueError): Section("section_property", parent=Property("P")) @@ -227,18 +227,18 @@ def test_children(self): sec.props[1] = "prop2" def test_id(self): - s = Section(name="S") - self.assertIsNotNone(s.id) + sec = Section(name="S") + self.assertIsNotNone(sec.id) - s = Section("S", oid="79b613eb-a256-46bf-84f6-207df465b8f7") - self.assertEqual(s.id, "79b613eb-a256-46bf-84f6-207df465b8f7") + sec = Section("S", oid="79b613eb-a256-46bf-84f6-207df465b8f7") + self.assertEqual(sec.id, "79b613eb-a256-46bf-84f6-207df465b8f7") - s = Section("S", oid="id") - self.assertNotEqual(s.id, "id") + sec = Section("S", oid="id") + self.assertNotEqual(sec.id, "id") # Make sure id cannot be reset programmatically. with self.assertRaises(AttributeError): - s.id = "someId" + sec.id = "someId" def test_new_id(self): sec = Section(name="sec") @@ -573,13 +573,13 @@ def test_merge_check(self): s_sec_one = Section(name="lvl", type="one", reference="ref", definition="def", parent=source) - s_sec_two = Section(name="unrelated", type="one", - reference="one", definition="one", parent=source) + _ = Section(name="unrelated", type="one", + reference="one", definition="one", parent=source) - d_sec_one = Section(name="lvl", type="one", - reference="ref", definition="def", parent=destination) - d_sec_two = Section(name="unrelated", type="two", - reference="two", definition="two", parent=destination) + _ = Section(name="lvl", type="one", + reference="ref", definition="def", parent=destination) + _ = Section(name="unrelated", type="two", + reference="two", definition="two", parent=destination) # Test Section child level definition check destination.merge_check(source, True) @@ -603,17 +603,17 @@ def test_merge_check(self): reference="ref2", definition="def2", parent=s_sec_one) s_sec_two = Section(name="unrelated", type="one", reference="one", definition="one", parent=source) - s_subsec_two = Section(name="lvl", type="two", - reference="none1", definition="none1", parent=s_sec_two) + _ = Section(name="lvl", type="two", + reference="none1", definition="none1", parent=s_sec_two) d_sec_one = Section(name="lvl", type="one", reference="ref", definition="def", parent=destination) - d_subsec_one = Section(name="lvl", type="two", - reference="ref2", definition="def2", parent=d_sec_one) + _ = Section(name="lvl", type="two", + reference="ref2", definition="def2", parent=d_sec_one) d_sec_two = Section(name="unrelated", type="two", reference="two", definition="two", parent=destination) - d_subsec_two = Section(name="lvl", type="two", - reference="none2", definition="none2", parent=d_sec_two) + _ = Section(name="lvl", type="two", + reference="none2", definition="none2", parent=d_sec_two) # Test Section 2nd child level definition check # Check no definition/reference ValueError between s_subsec_two and d_subsec_one @@ -655,10 +655,10 @@ def test_merge_check(self): destination = Section(name="destination") s_prop_one = Property(name="lvl one", unit="Hz", parent=source) - s_prop_two = Property(name="unrelated one", unit="one", parent=source) + _ = Property(name="unrelated one", unit="one", parent=source) - d_prop_one = Property(name="lvl one", unit="Hz", parent=destination) - d_prop_two = Property(name="unrelated two", unit="two", parent=destination) + _ = Property(name="lvl one", unit="Hz", parent=destination) + _ = Property(name="unrelated two", unit="two", parent=destination) # Test Property child level check destination.merge_check(source, True) @@ -676,13 +676,13 @@ def test_merge_check(self): s_subprop_one = Property(name="lvl one", unit="Hz", parent=s_sec_one) s_sec_two = Section(name="unrelated", type="one", parent=source) - s_subprop_two = Property(name="unrelated one", unit="one", parent=s_sec_two) + _ = Property(name="unrelated one", unit="one", parent=s_sec_two) d_sec_one = Section(name="lvl", type="one", parent=destination) - d_subprop_one = Property(name="lvl one", unit="Hz", parent=d_sec_one) + _ = Property(name="lvl one", unit="Hz", parent=d_sec_one) d_sec_two = Section(name="unrelated", type="two", parent=destination) - d_subprop_two = Property(name="unrelated one", unit="two", parent=d_sec_two) + _ = Property(name="unrelated one", unit="two", parent=d_sec_two) # Test Property 2nd child level definition check # Check no unit ValueError between s_subprop_two and d_subprop_one @@ -707,7 +707,7 @@ def test_merge(self): # -- First child level Section merge tests s_sec_one = Section(name="lvl", type="one", definition="def", parent=source) s_sec_two = Section(name="other", type="one", parent=source) - d_sec_one = Section(name="lvl", type="one", parent=destination) + _ = Section(name="lvl", type="one", parent=destination) self.assertEqual(len(destination), 1) self.assertIsNone(destination.sections["lvl"].definition) @@ -725,7 +725,7 @@ def test_merge(self): s_prop_one = Property(name="prop_one", unit="Hz", parent=source) s_prop_two = Property(name="prop_two", parent=source) - d_prop_one = Property(name="prop_one", parent=destination) + _ = Property(name="prop_one", parent=destination) self.assertEqual(len(destination.properties), 1) self.assertIsNone(destination.properties["prop_one"].unit) @@ -744,7 +744,7 @@ def test_merge(self): s_prop_two = Property(name="prop_two", parent=s_sec_one) d_sec_one = Section(name="lvl", type="one", parent=destination) - d_prop_one = Property(name="prop_one", parent=d_sec_one) + _ = Property(name="prop_one", parent=d_sec_one) self.assertEqual(len(destination.properties), 0) self.assertEqual(len(destination.sections["lvl"].properties), 1) @@ -763,10 +763,10 @@ def test_merge(self): destination = Section(name="destination") s_sec_one = Section(name="lvl", type="one", definition="def", parent=source) - s_sec_two = Section(name="other", type="one", parent=source) + _ = Section(name="other", type="one", parent=source) d_sec_one = Section(name="lvl", type="one", parent=destination) - s_subprop_one = Property(name="prop", value=[1, 2, 3], parent=s_sec_one) + _ = Property(name="prop", value=[1, 2, 3], parent=s_sec_one) d_subprop_one = Property(name="prop", value=["four", "five"], parent=d_sec_one) self.assertEqual(len(destination.sections), 1) diff --git a/test/test_terminology.py b/test/test_terminology.py new file mode 100644 index 00000000..053ee9be --- /dev/null +++ b/test/test_terminology.py @@ -0,0 +1,121 @@ +""" +Tests functions and classes from the odml terminology module. +""" + +import os +import unittest +import tempfile + +from glob import glob +from time import sleep +try: + from urllib.request import pathname2url +except ImportError: + from urllib import pathname2url + +from odml import Document, save, Section, terminology + +CACHE_DIR = os.path.join(tempfile.gettempdir(), "odml.cache") + + +class TestTerminology(unittest.TestCase): + + def setUp(self): + """ + Set up local temporary terminology files in a temporary folder + """ + tmp_dir = tempfile.mkdtemp("_odml") + tmp_name = os.path.basename(tmp_dir) + + main_name = "%s_main.xml" % tmp_name + main_file_path = os.path.join(tmp_dir, main_name) + main_url = "file://%s" % pathname2url(main_file_path) + + include_name = "%s_include.xml" % tmp_name + include_file_path = os.path.join(tmp_dir, include_name) + include_url = "file://%s" % pathname2url(include_file_path) + + include_doc = Document() + _ = Section(name="include_sec", type="test", parent=include_doc) + save(include_doc, include_file_path) + + main_doc = Document() + _ = Section(name="main_sec", type="test", include=include_url, parent=main_doc) + save(main_doc, main_file_path) + + self.main_terminology_url = main_url + self.temp_dir_base = tmp_name + + def tearDown(self): + """ + Remove all created files from the odml.cache to not cross pollute other tests. + The created tmp directory should be cleaned up automatically upon startup. + """ + temp_file_glob = "*%s*" % self.temp_dir_base + find_us = os.path.join(CACHE_DIR, temp_file_glob) + + for file_path in glob(find_us): + os.remove(file_path) + + @staticmethod + def _cache_files_map(file_filter="*"): + """ + Returns a dict mapping the basefilenames of cached odml files + to their md5 hash and mtime. + + :param file_filter: a valid glob to search for files in the odml cache directory. + The cache directory is provided and must not be part of the glob. + Default value is '*'. + + :return: dict of the format {filename: [md5_hash, mtime]} + """ + temp_file_glob = os.path.join(CACHE_DIR, file_filter) + + curr_map = {} + for file_path in glob(temp_file_glob): + split_name = os.path.basename(file_path).split('.') + file_mtime = os.path.getmtime(file_path) + curr_map[split_name[1]] = [split_name[0], file_mtime] + + return curr_map + + def test_terminology_refresh(self): + """ + Test terminology cache refresh using local files to detach + loading and resolving from the live online terminology repository. + """ + # Fetch current cache content specific to the two local terminologies + # With the default file glob '*' all files in the odml cache directory would be + # included in the test. + file_filter = "*%s*" % self.temp_dir_base + main_url = self.main_terminology_url + + # Initially load main and included file from temp directory into the odml cache directory + terminology.load(main_url) + + orig_map = self._cache_files_map(file_filter) + + # Test cache content does not change + terminology.load(main_url) + load_map = self._cache_files_map(file_filter) + + self.assertEqual(len(orig_map), len(load_map)) + for curr_file in orig_map: + self.assertIn(curr_file, load_map) + self.assertEqual(orig_map[curr_file], load_map[curr_file]) + + # Sleep is needed since the tests might be too fast to result in a + # different file mtime. macOS seems to require sleep time > 0.700. + sleep(0.800) + + # Test refresh loads same cached files but changes them. + # Different mtimes and id strings are sufficient. + terminology.refresh(main_url) + refresh_map = self._cache_files_map(file_filter) + self.assertEqual(len(orig_map), len(refresh_map)) + for curr_file in orig_map: + self.assertIn(curr_file, refresh_map) + # Check identical md5 hash + self.assertEqual(orig_map[curr_file][0], refresh_map[curr_file][0]) + # Check different mtime + self.assertLess(orig_map[curr_file][1], refresh_map[curr_file][1]) diff --git a/test/test_validation.py b/test/test_validation.py index 7b270d48..b58f13a1 100644 --- a/test/test_validation.py +++ b/test/test_validation.py @@ -1,7 +1,8 @@ -import unittest -import odml import os import sys +import unittest + +import odml import odml.validation import odml.terminology from . import test_samplefile as samplefile @@ -11,25 +12,21 @@ except ImportError: from io import StringIO -validate = odml.validation.Validation +Validate = odml.validation.Validation class TestValidation(unittest.TestCase): def setUp(self): self.doc = samplefile.SampleFileCreator().create_document() - self.maxDiff = None self.dir_path = os.path.dirname(os.path.realpath(__file__)) - def filter_repository_errors(self, errors): - return filter(lambda x: "A section should have an associated " - "repository" not in x.msg, errors) - - def test_errorfree(self): - res = validate(self.doc) - self.assertEqual(list(self.filter_repository_errors(res.errors)), []) + @staticmethod + def filter_repository_errors(errors): + find_msg = "A section should have an associated repository" + return filter(lambda x: find_msg not in x.msg, errors) - def assertError(self, res, err, filter_rep=True, filter_map=False): + def assertError(self, res, err, filter_rep=True): """ Passes only if err appears in res.errors """ @@ -48,13 +45,13 @@ def test_property_values_cardinality(self): # Test no caught warning on empty cardinality prop = odml.Property(name="prop_empty_cardinality", values=[1, 2, 3, 4], parent=sec) # Check that the current property is not in the list of validation warnings or errors - for err in validate(doc).errors: + for err in Validate(doc).errors: self.assertNotEqual(err.obj.id, prop.id) # Test no warning on valid cardinality prop = odml.Property(name="prop_valid_cardinality", values=[1, 2, 3, 4], val_cardinality=(2, 10), parent=sec) - for err in validate(doc).errors: + for err in Validate(doc).errors: self.assertNotEqual(err.obj.id, prop.id) # Test maximum value cardinality validation @@ -66,7 +63,7 @@ def test_property_values_cardinality(self): test_msg_base = "Property values cardinality violated" test_msg = "%s (maximum %s values, %s found)" % (test_msg_base, test_card, len(prop.values)) - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == prop.id: self.assertFalse(err.is_error) self.assertIn(test_msg, err.msg) @@ -78,8 +75,9 @@ def test_property_values_cardinality(self): prop = odml.Property(name="prop_invalid_min_val", values=test_val, val_cardinality=test_card, parent=sec) - test_msg = "%s (minimum %s values, %s found)" % (test_msg_base, test_card[0], len(prop.values)) - for err in validate(doc).errors: + test_msg = "%s (minimum %s values, %s found)" % (test_msg_base, test_card[0], + len(prop.values)) + for err in Validate(doc).errors: if err.obj.id == prop.id: self.assertFalse(err.is_error) self.assertIn(test_msg, err.msg) @@ -91,14 +89,14 @@ def test_section_properties_cardinality(self): # Test no caught warning on empty cardinality sec = odml.Section(name="prop_empty_cardinality", type="test", parent=doc) # Check that the current section did not throw any properties cardinality warnings - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id: self.assertNotIn(msg_base, err.msg) # Test no warning on valid cardinality sec = odml.Section(name="prop_valid_cardinality", prop_cardinality=(1, 2), parent=doc) _ = odml.Property(parent=sec) - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id: self.assertNotIn(msg_base, err.msg) @@ -113,7 +111,7 @@ def test_section_properties_cardinality(self): # Once ValidationErrors provide validation ids, the following can be simplified. found = False - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id and msg_base in err.msg: self.assertFalse(err.is_error) self.assertIn(test_msg, err.msg) @@ -132,7 +130,7 @@ def test_section_properties_cardinality(self): # Once ValidationErrors provide validation ids, the following can be simplified. found = False - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id and msg_base in err.msg: self.assertFalse(err.is_error) self.assertIn(test_msg, err.msg) @@ -147,14 +145,14 @@ def test_section_sections_cardinality(self): # Test no caught warning on empty cardinality sec = odml.Section(name="sec_empty_cardinality", type="test", parent=doc) # Check that the current section did not throw any sections cardinality warnings - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id: self.assertNotIn(msg_base, err.msg) # Test no warning on valid cardinality sec = odml.Section(name="sec_valid_cardinality", sec_cardinality=(1, 2), parent=doc) _ = odml.Section(name="sub_sec_valid_cardinality", type="test", parent=sec) - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id: self.assertNotIn(msg_base, err.msg) @@ -170,7 +168,7 @@ def test_section_sections_cardinality(self): # Once ValidationErrors provide validation ids, the following can be simplified. found = False - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id and msg_base in err.msg: self.assertFalse(err.is_error) self.assertIn(test_msg, err.msg) @@ -189,7 +187,7 @@ def test_section_sections_cardinality(self): # Once ValidationErrors provide validation ids, the following can be simplified. found = False - for err in validate(doc).errors: + for err in Validate(doc).errors: if err.obj.id == sec.id and msg_base in err.msg: self.assertFalse(err.is_error) self.assertIn(test_msg, err.msg) @@ -199,7 +197,7 @@ def test_section_sections_cardinality(self): def test_section_in_terminology(self): doc = samplefile.parse("""s1[T1]""") - res = validate(doc) + res = Validate(doc) self.assertError(res, "A section should have an associated repository", filter_rep=False) @@ -208,7 +206,7 @@ def test_section_in_terminology(self): - S1[T1] """) doc.sections[0].repository = 'map' - res = validate(doc) + res = Validate(doc) # self.assertEqual(list(self.filter_mapping_errors(res.errors)), []) self.assertEqual(res.errors, []) @@ -234,7 +232,7 @@ def test_property_in_terminology(self): - P1 """) doc.repository = 'term' - res = validate(doc) + res = Validate(doc) self.assertEqual(res.errors, []) doc = samplefile.parse(""" @@ -243,18 +241,18 @@ def test_property_in_terminology(self): - P1 """) doc.repository = 'term' - res = validate(doc) + res = Validate(doc) self.assertError(res, "Property 'p1' not found in terminology") def test_property_values(self): # different units doc = samplefile.parse("""s1[t1]""") - p = odml.Property(name="p1", value=[0, 1]) - doc["s1"].append(p) + prop = odml.Property(name="p1", value=[0, 1]) + doc["s1"].append(prop) # missing dependency - p.dependency = "p2" - res = validate(doc) + prop.dependency = "p2" + res = Validate(doc) self.assertError(res, "non-existent dependency object") def test_property_unique_ids(self): @@ -269,7 +267,7 @@ def test_property_unique_ids(self): cprop = prop.clone(keep_id=True) sec_two.append(cprop) - res = validate(doc) + res = Validate(doc) self.assertError(res, "Duplicate id in Property") def test_section_unique_ids(self): @@ -282,7 +280,7 @@ def test_section_unique_ids(self): csec = sec.clone(keep_id=True) sec.append(csec) - res = validate(doc) + res = Validate(doc) self.assertError(res, "Duplicate id in Section") def test_section_name_readable(self): @@ -292,7 +290,7 @@ def test_section_name_readable(self): doc = odml.Document() sec = odml.Section("sec", parent=doc) sec.name = sec.id - res = validate(doc) + res = Validate(doc) self.assertError(res, "Name should be readable") def test_property_name_readable(self): @@ -303,7 +301,7 @@ def test_property_name_readable(self): sec = odml.Section("sec", parent=doc) prop = odml.Property("prop", parent=sec) prop.name = prop.id - res = validate(doc) + res = Validate(doc) self.assertError(res, "Name should be readable") def test_standalone_section(self): @@ -313,7 +311,7 @@ def test_standalone_section(self): """ sec_one = odml.Section("sec1") - res = validate(sec_one) + res = Validate(sec_one) self.assertError(res, "Section type not specified") def test_standalone_property(self): @@ -324,8 +322,8 @@ def test_standalone_property(self): prop = odml.Property() prop.type = "" - errs = list(filter(lambda x: x.is_error, validate(prop).errors)) - self.assertEquals(len(errs), 0) + errs = list(filter(lambda x: x.is_error, Validate(prop).errors)) + self.assertEqual(len(errs), 0) def test_section_init(self): """ @@ -347,48 +345,47 @@ def test_prop_string_values(self): raise validation warning. """ - prop0 = odml.Property(name='words', dtype="string", - values=['-13', '101', '-11', 'hello']) - self.assertEquals(len(validate(prop0).errors), 0) + val = ['-13', '101', '-11', 'hello'] + prop0 = odml.Property(name='words', dtype="string", values=val) + self.assertEqual(len(Validate(prop0).errors), 0) msg_base = 'Dtype of property "%s" currently is "string", but might fit dtype "%s"!' - prop1 = odml.Property(name='members', dtype="string", - values=['-13', '101', '-11', '0', '-8']) - self.assertError(validate(prop1), msg_base % ("members", "int")) + val = ['-13', '101', '-11', '0', '-8'] + prop1 = odml.Property(name='members', dtype="string", values=val) + self.assertError(Validate(prop1), msg_base % ("members", "int")) - prop2 = odml.Property(name='potential', dtype="string", - values=['-4.8', '10.0', '-11.9', '-10.0', '18.0']) - self.assertError(validate(prop2), msg_base % ("potential", "float")) + val = ['-4.8', '10.0', '-11.9', '-10.0', '18.0'] + prop2 = odml.Property(name='potential', dtype="string", values=val) + self.assertError(Validate(prop2), msg_base % ("potential", "float")) - prop3 = odml.Property(name='dates', dtype="string", - values=['1997-12-14', '00-12-14', '89-07-04']) - self.assertError(validate(prop3), msg_base % ("dates", "date")) + val = ['1997-12-14', '00-12-14', '89-07-04'] + prop3 = odml.Property(name='dates', dtype="string", values=val) + self.assertError(Validate(prop3), msg_base % ("dates", "date")) - prop4 = odml.Property(name='datetimes', dtype="string", - values=['97-12-14 11:11:11', '97-12-14 12:12', '1997-12-14 03:03']) - self.assertError(validate(prop4), msg_base % ("datetimes", "datetime")) + val = ['97-12-14 11:11:11', '97-12-14 12:12', '1997-12-14 03:03'] + prop4 = odml.Property(name='datetimes', dtype="string", values=val) + self.assertError(Validate(prop4), msg_base % ("datetimes", "datetime")) - prop5 = odml.Property(name='times', dtype="string", - values=['11:11:11', '12:12:12', '03:03:03']) - self.assertError(validate(prop5), msg_base % ("times", "time")) + val = ['11:11:11', '12:12:12', '03:03:03'] + prop5 = odml.Property(name='times', dtype="string", values=val) + self.assertError(Validate(prop5), msg_base % ("times", "time")) - prop6 = odml.Property(name='sent', dtype="string", - values=['False', True, 'TRUE', False, 't']) - self.assertError(validate(prop6), msg_base % ("sent", "boolean")) + val = ['False', True, 'TRUE', False, 't'] + prop6 = odml.Property(name='sent', dtype="string", values=val) + self.assertError(Validate(prop6), msg_base % ("sent", "boolean")) - prop7 = odml.Property(name='texts', dtype="string", - values=['line1\n line2', 'line3\n line4', '\nline5\nline6']) - self.assertError(validate(prop7), msg_base % ("texts", "text")) + val = ['line1\n line2', 'line3\n line4', '\nline5\nline6'] + prop7 = odml.Property(name='texts', dtype="string", values=val) + self.assertError(Validate(prop7), msg_base % ("texts", "text")) - prop8 = odml.Property(name="Location", dtype='string', - values=['(39.12; 67.19)', '(39.12; 67.19)', '(39.12; 67.18)']) - self.assertError(validate(prop8), msg_base % ("Location", "2-tuple")) + val = ['(39.12; 67.19)', '(39.12; 67.19)', '(39.12; 67.18)'] + prop8 = odml.Property(name="Location", dtype='string', values=val) + self.assertError(Validate(prop8), msg_base % ("Location", "2-tuple")) - prop9 = odml.Property(name="Coos", dtype='string', - values=['(39.12; 89; 67.19)', '(39.12; 78; 67.19)', - '(39.12; 56; 67.18)']) - self.assertError(validate(prop9), msg_base % ("Coos", "3-tuple")) + val = ['(39.12; 89; 67.19)', '(39.12; 78; 67.19)', '(39.12; 56; 67.18)'] + prop9 = odml.Property(name="Coos", dtype='string', values=val) + self.assertError(Validate(prop9), msg_base % ("Coos", "3-tuple")) def load_section_validation(self, doc): filter_func = lambda x: x.msg == filter_msg and x.obj.name == filter_name @@ -396,12 +393,12 @@ def load_section_validation(self, doc): # Check error for deliberate empty section type filter_msg = "Missing required attribute 'type'" filter_name = "sec_type_empty" - self.assertGreater(len(list(filter(filter_func, validate(doc).errors))), 0) + self.assertGreater(len(list(filter(filter_func, Validate(doc).errors))), 0) # Check warning for not specified section type filter_msg = "Section type not specified" filter_name = "sec_type_undefined" - self.assertGreater(len(list(filter(filter_func, validate(doc).errors))), 0) + self.assertGreater(len(list(filter(filter_func, Validate(doc).errors))), 0) def test_load_section_xml(self): """ @@ -436,7 +433,7 @@ def test_load_section_yaml(self): def load_dtypes_validation(self, doc): msg_base = 'Dtype of property "%s" currently is "string", but might fit dtype "%s"!' - doc_val = validate(doc) + doc_val = Validate(doc) self.assertError(doc_val, msg_base % ("members_no", "int")) self.assertError(doc_val, msg_base % ("potential_no", "float")) self.assertError(doc_val, msg_base % ("dates_no", "date")) diff --git a/test/test_version_converter.py b/test/test_version_converter.py index 49dc0882..43887c4a 100644 --- a/test/test_version_converter.py +++ b/test/test_version_converter.py @@ -3,15 +3,10 @@ import shutil import tempfile import unittest -try: - import urllib.request as urllib2 - from urllib.request import pathname2url -except ImportError: - import urllib2 - from urllib import pathname2url from contextlib import contextmanager from lxml import etree as ET + from odml.terminology import REPOSITORY_BASE from odml.tools.converters import VersionConverter @@ -118,8 +113,8 @@ def test_convert_odml_file(self): self.assertEqual(prop.find("type"), None) file = io.StringIO(unicode(self.doc)) - vc = self.VC(file) - tree = vc._convert(vc._parse_xml()) + converter = self.VC(file) + tree = converter._convert(converter._parse_xml()) root = tree.getroot() prop = root.find("section").find("property") val_elems = [] @@ -146,12 +141,10 @@ def test_convert_odml_file_document(self): """ dir_path = os.path.dirname(os.path.realpath(__file__)) - repo_file = os.path.join(dir_path, "resources", - "local_repository_file_v1.1.xml") + repo_file = os.path.join(dir_path, "resources", "local_repository_file_v1.1.xml") local_url = "file://%s" % repo_file - repo_old_file = os.path.join(dir_path, "resources", - "local_repository_file_v1.0.xml") + repo_old_file = os.path.join(dir_path, "resources", "local_repository_file_v1.0.xml") local_old_url = "file://%s" % repo_old_file doc = """ @@ -185,8 +178,8 @@ def test_convert_odml_file_document(self): """ % local_old_url file = io.StringIO(unicode(doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) root = conv_doc.getroot() # Test export of Document tags, repository is excluded self.assertEqual(len(root.findall("author")), 1) @@ -201,19 +194,19 @@ def test_convert_odml_file_document(self): # Test warning message on non-importable repository file = io.StringIO(unicode(invalid_repo_doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) root = conv_doc.getroot() self.assertEqual(root.findall("repository")[0].text, "Unresolvable") - self.assertIn("not odML v1.1 compatible", vc.conversion_log[0]) + self.assertIn("not odML v1.1 compatible", converter.conversion_log[0]) # Test warning message on old repository file = io.StringIO(unicode(old_repo_doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) root = conv_doc.getroot() self.assertEqual(root.findall("repository")[0].text, local_old_url) - self.assertIn("not odML v1.1 compatible", vc.conversion_log[0]) + self.assertIn("not odML v1.1 compatible", converter.conversion_log[0]) def test_convert_odml_file_section(self): """Test proper conversion of the odml.Section entity from @@ -224,12 +217,10 @@ def test_convert_odml_file_section(self): """ dir_path = os.path.dirname(os.path.realpath(__file__)) - repo_file = os.path.join(dir_path, "resources", - "local_repository_file_v1.1.xml") + repo_file = os.path.join(dir_path, "resources", "local_repository_file_v1.1.xml") local_url = "file://%s" % repo_file - repo_old_file = os.path.join(dir_path, "resources", - "local_repository_file_v1.0.xml") + repo_old_file = os.path.join(dir_path, "resources", "local_repository_file_v1.0.xml") local_old_url = "file://%s" % repo_old_file doc = """ @@ -268,8 +259,8 @@ def test_convert_odml_file_section(self): """ % (local_url, local_url) file = io.StringIO(unicode(doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) root = conv_doc.getroot() root_id = root.findall("id") @@ -318,11 +309,11 @@ def test_convert_odml_file_section(self): """ % local_old_url file = io.StringIO(unicode(doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) sec = conv_doc.getroot().findall("section") self.assertEqual(sec[0].find("repository").text, local_old_url) - self.assertIn("not odML v1.1 compatible", vc.conversion_log[0]) + self.assertIn("not odML v1.1 compatible", converter.conversion_log[0]) # Test presence of v1.0 include tag and warning log entry doc = """ @@ -334,12 +325,12 @@ def test_convert_odml_file_section(self): """ % local_old_url file = io.StringIO(unicode(doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) sec = conv_doc.getroot().findall("section") self.assertEqual(sec[0].find("include").text, local_old_url) - self.assertIn("not odML v1.1 compatible", vc.conversion_log[0]) + self.assertIn("not odML v1.1 compatible", converter.conversion_log[0]) def test_convert_odml_file_property(self): """Test proper conversion of the odml.Property entity from @@ -375,8 +366,8 @@ def test_convert_odml_file_property(self): """ file = io.StringIO(unicode(doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) root = conv_doc.getroot() sec = root.findall("section") @@ -540,8 +531,8 @@ def test_convert_odml_file_value(self): """ file = io.StringIO(unicode(doc)) - vc = self.VC(file) - conv_doc = vc._convert(vc._parse_xml()) + converter = self.VC(file) + conv_doc = converter._convert(converter._parse_xml()) root = conv_doc.getroot() root_id = root.findall("id") self.assertEqual(len(root_id), 1) @@ -659,7 +650,6 @@ def test_convert_odml_file_value(self): self.assertEqual(len(prop.findall("id")), 1) self.assertNotEqual(prop.find("id").text, "1") - def test_parse_dict_document(self): # Test appending tags; not appending empty sections doc_dict = {'Document': {'author': 'HPL', 'sections': []}} @@ -757,24 +747,23 @@ def test_handle_repository(self): # Test working and valid repository link repo.text = '/'.join([REPOSITORY_BASE, 'v1.1', 'analysis', 'analysis.xml']) - vc = self.VC("") - self.assertIsNone(vc._handle_repository(repo)) - self.assertEqual(vc.conversion_log, []) + converter = self.VC("") + self.assertIsNone(converter._handle_repository(repo)) + self.assertEqual(converter.conversion_log, []) # Test replaced working repository link repo.text = '/'.join([REPOSITORY_BASE, 'v1.0', 'analysis', 'analysis.xml']) - self.assertIsNone(vc._handle_repository(repo)) - self.assertEqual(repo.text, '/'.join([REPOSITORY_BASE, 'v1.1', - 'analysis', 'analysis.xml'])) - self.assertEqual(len(vc.conversion_log), 1) - self.assertTrue("[Info]" in vc.conversion_log[0]) + self.assertIsNone(converter._handle_repository(repo)) + self.assertEqual(repo.text, '/'.join([REPOSITORY_BASE, 'v1.1', 'analysis', 'analysis.xml'])) + self.assertEqual(len(converter.conversion_log), 1) + self.assertTrue("[Info]" in converter.conversion_log[0]) # Test invalid repository link invalid = "I am leading nowhere" repo.text = invalid - self.assertIsNone(vc._handle_repository(repo)) - self.assertEqual(len(vc.conversion_log), 2) - self.assertTrue("[Warning]" in vc.conversion_log[1]) + self.assertIsNone(converter._handle_repository(repo)) + self.assertEqual(len(converter.conversion_log), 2) + self.assertTrue("[Warning]" in converter.conversion_log[1]) self.assertEqual(repo.text, invalid) def test_handle_include(self): @@ -782,24 +771,23 @@ def test_handle_include(self): # Test working and valid repository link repo.text = '/'.join([REPOSITORY_BASE, 'v1.1', 'analysis', 'analysis.xml']) - vc = self.VC("") - self.assertIsNone(vc._handle_include(repo)) - self.assertEqual(vc.conversion_log, []) + converter = self.VC("") + self.assertIsNone(converter._handle_include(repo)) + self.assertEqual(converter.conversion_log, []) # Test replaced working repository link repo.text = '/'.join([REPOSITORY_BASE, 'v1.0', 'analysis', 'analysis.xml']) - self.assertIsNone(vc._handle_include(repo)) - self.assertEqual(repo.text, '/'.join([REPOSITORY_BASE, 'v1.1', - 'analysis', 'analysis.xml'])) - self.assertEqual(len(vc.conversion_log), 1) - self.assertTrue("[Info]" in vc.conversion_log[0]) + self.assertIsNone(converter._handle_include(repo)) + self.assertEqual(repo.text, '/'.join([REPOSITORY_BASE, 'v1.1', 'analysis', 'analysis.xml'])) + self.assertEqual(len(converter.conversion_log), 1) + self.assertTrue("[Info]" in converter.conversion_log[0]) # Test invalid repository link invalid = "I am leading nowhere" repo.text = invalid - self.assertIsNone(vc._handle_include(repo)) - self.assertEqual(len(vc.conversion_log), 2) - self.assertTrue("[Warning]" in vc.conversion_log[1]) + self.assertIsNone(converter._handle_include(repo)) + self.assertEqual(len(converter.conversion_log), 2) + self.assertTrue("[Warning]" in converter.conversion_log[1]) self.assertEqual(repo.text, invalid) def test_convert_xml_file(self):