coveralls: 
[![Coverage Status](https://coveralls.io/builds/29823976/badge)](https://coveralls.io/builds/29823976)

Coverage decreased (-0.2%) to 75.526% when pulling **108639e9215873a0e11692fed1af230caac7b813 on fschrader1992:rdf** into **d9d52231dd5fb1c7b400736cfe797ba487517c57 on G-Node:master**.

fschrader1992: Checks for Code Quality:
- [x] Pylint
- [x] Rebase onto GNODE Master
- [x] Repeat Local Tests Python3.8
- [x] Repeat Local Tests Python2.7
diff --git a/odml/terminology.py b/odml/terminology.py
index 2076fa2..35d2140 100644
--- a/odml/terminology.py
+++ b/odml/terminology.py
@@ -24,12 +24,13 @@ REPOSITORY = '/'.join([REPOSITORY_BASE, 'v1.1', 'terminologies.xml'])
 CACHE_AGE = datetime.timedelta(days=1)
 
 
-def cache_load(url):
+def cache_load(url, replace_file=False):
     """
     Loads the url and store it in a temporary cache directory
     subsequent requests for this url will use the cached version.
 
     :param url: URL from where to load an odML terminology file from.
+    :param replace_file: True, if file should be reloaded
     """
     filename = '.'.join([md5(url.encode()).hexdigest(), os.path.basename(url)])
     cache_dir = os.path.join(tempfile.gettempdir(), "odml.cache")
@@ -41,8 +42,9 @@ def cache_load(url):
                 raise
     cache_file = os.path.join(cache_dir, filename)
     if not os.path.exists(cache_file) \
-       or datetime.datetime.fromtimestamp(os.path.getmtime(cache_file)) < \
-       datetime.datetime.now() - CACHE_AGE:
+            or replace_file \
+            or datetime.datetime.fromtimestamp(os.path.getmtime(cache_file)) < \
+            datetime.datetime.now() - CACHE_AGE:
         try:
             data = urllib2.urlopen(url).read()
             if sys.version_info.major > 2:
@@ -64,6 +66,7 @@ class Terminologies(dict):
     browsing and importing of full or partial odML terminologies.
     """
     loading = {}
+    reload_cache = False
 
     def load(self, url):
         """
@@ -92,7 +95,7 @@ class Terminologies(dict):
                  It will silently return None, if any exceptions
                  occur to enable loading of nested odML files.
         """
-        file_obj = cache_load(url)
+        file_obj = cache_load(url, self.reload_cache)
         if file_obj is None:
             print("did not successfully load '%s'" % url)
             return
@@ -117,10 +120,23 @@ class Terminologies(dict):
         self.loading[url] = threading.Thread(target=self._load, args=(url,))
         self.loading[url].start()
 
+    def refresh(self, url):
+        """
+        Deletes and reloads all cached odML XML files given in the
+        terminology file from a URL.
+
+        :param url: location of an odML XML file.
+        """
+        self.reload_cache = True
+        self.clear()
+        self.load(url)
+        self.reload_cache = False
+
 
 terminologies = Terminologies()
 load = terminologies.load
 deferred_load = terminologies.deferred_load
+refresh = terminologies.refresh
 
 
 if __name__ == "__main__":

[1.4] Terminology cache cannot be refreshed
Currently the Terminology cache cannot be refreshed.
diff --git a/test/test_doc.py b/test/test_doc.py
index 69969e4..984f134 100644
--- a/test/test_doc.py
+++ b/test/test_doc.py
@@ -1,6 +1,9 @@
 import datetime
 import os
 import unittest
+import tempfile
+import odml.terminology
+from hashlib import md5
 try:
     from urllib.request import pathname2url
 except ImportError:
@@ -109,6 +112,32 @@ class TestSection(unittest.TestCase):
         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, [])
diff --git a/test/test_parser_odml.py b/test/test_parser_odml.py
index 3bf8417..67cedf4 100644
--- a/test/test_parser_odml.py
+++ b/test/test_parser_odml.py
@@ -8,6 +8,7 @@ import shutil
 import tempfile
 import unittest
 
+from odml import Document, Section, Property
 from odml.tools import odmlparser
 
 
@@ -82,6 +83,10 @@ class TestOdmlParser(unittest.TestCase):
         self.assertEqual(json_doc, self.odml_doc)
 
     def test_rdf_file(self):
+        """
+        Test comparison of document before and after rdf-conversion
+        """
+
         self.rdf_writer.write_file(self.odml_doc, self.rdf_file)
         rdf_doc = self.rdf_reader.from_file(self.rdf_file, "xml")
 
@@ -101,6 +106,45 @@ class TestOdmlParser(unittest.TestCase):
         with self.assertRaises(ValueError):
             self.rdf_reader.from_file(self.rdf_file)
 
+        doc = Document()
+        sec1 = Section(name="sec1", type="int", parent=doc)
+        Property(name="prop11", values=[1, 2, 3], dtype="int", parent=sec1)
+        Property(name="prop12", values=[1.1, 2.2, 3.3], dtype="float", parent=sec1)
+        Property(name="prop13", values=["a", "b", "c"], dtype="string", parent=sec1)
+        sec2 = Section(name="sec2", type="int", parent=doc)
+        Property(name="prop21", values=[1, 2, 3], dtype="int", parent=sec2)
+        Property(name="prop22", values=[1.1, 2.2, 3.3], dtype="float", parent=sec2)
+        Property(name="prop23", values=["a", "b", "c"], dtype="string", parent=sec2)
+        sec3 = Section(name="sec3", type="int", parent=doc)
+        Property(name="prop31", values=[1, 2, 3], dtype="int", parent=sec3)
+        Property(name="prop32", values=[1.1, 2.2, 3.3], dtype="float", parent=sec3)
+        Property(name="prop33", values=["a", "b", "c"], dtype="string", parent=sec3)
+        self.rdf_writer.write_file(doc, self.rdf_file)
+        rdf_doc = self.rdf_reader.from_file(self.rdf_file, "xml")
+
+        self.assertEqual(doc, rdf_doc[0])
+        self.assertEqual(len(rdf_doc), 1)
+        self.assertEqual(len(rdf_doc[0].sections), 3)
+
+        self.assertIn(doc.sections[0].name, rdf_doc[0].sections)
+        self.assertIn(doc.sections[1].name, rdf_doc[0].sections)
+        self.assertIn(doc.sections[2].name, rdf_doc[0].sections)
+        rdf_sec1 = rdf_doc[0].sections[doc.sections[0].name]
+        self.assertEqual(len(rdf_sec1.properties), 3)
+        self.assertIn(doc.sections[0].properties[0].name, rdf_sec1.properties)
+        self.assertIn(doc.sections[0].properties[1].name, rdf_sec1.properties)
+        self.assertIn(doc.sections[0].properties[1].name, rdf_sec1.properties)
+        rdf_sec2 = rdf_doc[0].sections[doc.sections[1].name]
+        self.assertEqual(len(rdf_sec2.properties), 3)
+        self.assertIn(doc.sections[1].properties[0].name, rdf_sec2.properties)
+        self.assertIn(doc.sections[1].properties[1].name, rdf_sec2.properties)
+        self.assertIn(doc.sections[1].properties[1].name, rdf_sec2.properties)
+        rdf_sec3 = rdf_doc[0].sections[doc.sections[2].name]
+        self.assertEqual(len(rdf_sec3.properties), 3)
+        self.assertIn(doc.sections[2].properties[0].name, rdf_sec3.properties)
+        self.assertIn(doc.sections[2].properties[1].name, rdf_sec3.properties)
+        self.assertIn(doc.sections[2].properties[1].name, rdf_sec3.properties)
+
     def test_xml_string(self):
         # Read from string
         author = "HPL"

pip install -e .
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y libxml2-dev libxslt1-dev
3.9
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
docopt==0.6.2
exceptiongroup==1.2.2
iniconfig==2.1.0
isodate==0.7.2
lxml==5.3.1
-e git+https://github.com/G-Node/python-odml.git@01fb08abb62e8ab4fd4b0390e280e05ec150cc4c#egg=odML
packaging==24.2
pathlib==1.0.1
pluggy==1.5.0
pyparsing==3.2.3
pytest==8.3.5
PyYAML==6.0.2
rdflib==7.1.4
tomli==2.2.1

name: python-odml
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - docopt==0.6.2
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - isodate==0.7.2
      - lxml==5.3.1
      - packaging==24.2
      - pathlib==1.0.1
      - pluggy==1.5.0
      - pyparsing==3.2.3
      - pytest==8.3.5
      - pyyaml==6.0.2
      - rdflib==7.1.4
      - tomli==2.2.1
prefix: /opt/conda/envs/python-odml

test/test_doc.py::TestSection::test_terminology_refresh
test/test_parser_odml.py::TestOdmlParser::test_rdf_file
test/test_doc.py::TestSection::test_append test/test_doc.py::TestSection::test_comparison test/test_doc.py::TestSection::test_create_section test/test_doc.py::TestSection::test_date test/test_doc.py::TestSection::test_extend test/test_doc.py::TestSection::test_get_terminology_equivalent test/test_doc.py::TestSection::test_id test/test_doc.py::TestSection::test_insert test/test_doc.py::TestSection::test_new_id test/test_doc.py::TestSection::test_simple_attributes test/test_parser_odml.py::TestOdmlParser::test_json_file test/test_parser_odml.py::TestOdmlParser::test_json_string test/test_parser_odml.py::TestOdmlParser::test_json_yaml_xml test/test_parser_odml.py::TestOdmlParser::test_rdf_string test/test_parser_odml.py::TestOdmlParser::test_xml_file test/test_parser_odml.py::TestOdmlParser::test_xml_string test/test_parser_odml.py::TestOdmlParser::test_yaml_file test/test_parser_odml.py::TestOdmlParser::test_yaml_string
odml/terminology.py
odml/terminology.py