diff --git a/pyclarity_lims/descriptors.py b/pyclarity_lims/descriptors.py
index c2ce1ad..1c4eea6 100644
--- a/pyclarity_lims/descriptors.py
+++ b/pyclarity_lims/descriptors.py
@@ -78,7 +78,8 @@ class XmlDictionary(XmlMutable, dict):
 
     def clear(self):
         dict.clear(self)
-        self.rootnode(self.instance).clear()
+        for elem in self._elems:
+            self.rootnode(self.instance).remove(elem)
         self._update_elems()
 
     def _update_elems(self):
@@ -337,18 +338,21 @@ class PlacementDictionary(XmlDictionary):
                 break
 
 
-class SubTagDictionary(XmlDictionary):
+class SubTagDictionary(XmlDictionary, Nestable):
     """Dictionary of xml sub element where the key is the tag
     and the value is the text of the sub element.
     """
     def __init__(self, instance, tag, **kwargs):
-        self.tag = tag
+        # In case extra nesting is provided
+        nesting = kwargs.get('nesting', [])
+        nesting.append(tag)
+        Nestable.__init__(self, nesting=nesting)
         XmlDictionary.__init__(self, instance)
 
     def _update_elems(self):
-        tag_node = self.rootnode(self.instance).find(self.tag)
-        if tag_node:
-            self._elems = tag_node.getchildren()
+        root_node = self.rootnode(self.instance)
+        if root_node:
+            self._elems = root_node.getchildren()
         else:
             self._elems = []
 
@@ -358,20 +362,18 @@ class SubTagDictionary(XmlDictionary):
     def _setitem(self, key, value):
         if not isinstance(key, str):
             raise ValueError()
-        tag_node = self.rootnode(self.instance).find(self.tag)
-        if tag_node is None:
-            tag_node = ElementTree.SubElement(self.rootnode(self.instance), self.tag)
+        root_node = self.rootnode(self.instance)
 
-        elem = tag_node.find(key)
+        elem = root_node.find(key)
         if elem is None:
-            elem = ElementTree.SubElement(tag_node, key)
+            elem = ElementTree.SubElement(root_node, key)
         elem.text = value
 
     def _delitem(self, key):
-        tag_node = self.rootnode(self.instance).find(self.tag)
+        root_node = self.rootnode(self.instance)
         for node in self._elems:
             if node.tag == key:
-                tag_node.remove(node)
+                root_node.remove(node)
                 break
 
 
@@ -437,7 +439,8 @@ class XmlList(XmlMutable, list):
     def clear(self):
         # python 2.7 does not have a clear function for list
         del self[:]
-        self.rootnode(self.instance).clear()
+        for elem in self._elems:
+            self.rootnode(self.instance).remove(elem)
         self._update_elems()
 
     def __add__(self, other_list):

UdfConfig presets clear method clears the entire UdfConfig object
Calling the UdfConfig.preset.clear() method seems to clear values from the entire UdfConfig object. Even if I set the preset list manually to a new empty list the object is also cleared...Is this expected?
diff --git a/tests/test_descriptors.py b/tests/test_descriptors.py
index e4cee66..bd8a42f 100644
--- a/tests/test_descriptors.py
+++ b/tests/test_descriptors.py
@@ -191,6 +191,8 @@ class TestStringAttributeDescriptor(TestDescriptor):
         assert instance_new.root.attrib['name'] == "test name2"
 
 
+
+
 class TestStringListDescriptor(TestDescriptor):
     def setUp(self):
         et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -368,7 +370,7 @@ class TestUdfDictionary(TestCase):
             assert (k, self.dict1[k]) in expected_content
 
 
-class TestPlacementDictionary(TestCase):
+class TestPlacementDictionary(TestDescriptor):
 
     def setUp(self):
         et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -376,6 +378,7 @@ class TestPlacementDictionary(TestCase):
 <placement uri="http://testgenologics.com:4040/api/v2/artifacts/a1" limsid="a1">
 <value>A:1</value>
 </placement>
+<other>thing</other>
 </test-entry>""")
         self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
         self.instance1 = Mock(root=et, lims=self.lims)
@@ -410,6 +413,15 @@ class TestPlacementDictionary(TestCase):
         del self.dict1['A:1']
         assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 0
 
+    def test_clear(self):
+        el = EntityList(self.instance1, 'artifact', Artifact)
+        sd = self._make_desc(StringDescriptor, 'other')
+        assert sd.__get__(self.instance1, None) == "thing"
+        assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 1
+        self.dict1.clear()
+        assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 0
+        assert sd.__get__(self.instance1, None) == "thing"
+
 
 class TestSubTagDictionary(TestCase):
 
@@ -424,20 +436,32 @@ class TestSubTagDictionary(TestCase):
         self.instance1 = Mock(root=et, lims=self.lims)
         self.dict1 = SubTagDictionary(self.instance1, tag='test-tag')
 
+        et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+        <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
+        </test-entry>""")
+        self.instance2 = Mock(root=et, lims=self.lims)
+        self.dict2 = SubTagDictionary(self.instance2, tag='test-tag')
+
     def test___getitem__(self):
         assert self.dict1['key1'] == 'value1'
 
     def test___setitem__(self):
-        assert len(self.dict1.rootnode(self.dict1.instance).find('test-tag')) == 1
-        assert self.dict1.rootnode(self.dict1.instance).find('test-tag').find('key1').text == 'value1'
+        assert len(self.dict1.rootnode(self.dict1.instance)) == 1
+        assert self.dict1.rootnode(self.dict1.instance).find('key1').text == 'value1'
         self.dict1['key1'] = 'value11'
-        assert len(self.dict1.rootnode(self.dict1.instance).find('test-tag')) == 1
-        assert self.dict1.rootnode(self.dict1.instance).find('test-tag').find('key1').text == 'value11'
+        assert len(self.dict1.rootnode(self.dict1.instance)) == 1
+        assert self.dict1.rootnode(self.dict1.instance).find('key1').text == 'value11'
         self.dict1['key2'] = 'value2'
-        assert len(self.dict1.rootnode(self.dict1.instance).find('test-tag')) == 2
-        assert self.dict1.rootnode(self.dict1.instance).find('test-tag').find('key2').text == 'value2'
+        assert len(self.dict1.rootnode(self.dict1.instance)) == 2
+        assert self.dict1.rootnode(self.dict1.instance).find('key2').text == 'value2'
         assert self.dict1['key2'] == 'value2'
 
+    def test___setitem__from_empty(self):
+        assert len(self.dict2.rootnode(self.dict2.instance)) == 0
+        self.dict2['key1'] = 'value1'
+        assert self.dict2.rootnode(self.dict2.instance).find('key1').text == 'value1'
+        assert len(self.dict2.rootnode(self.dict2.instance)) == 1
+
 
 class TestXmlElementAttributeDict(TestCase):
     def setUp(self):
@@ -502,13 +526,14 @@ class TestXmlPooledInputDict(TestCase):
         assert len(self.dict1.rootnode(self.dict1.instance)) == 3
 
 
-class TestEntityList(TestCase):
+class TestEntityList(TestDescriptor):
 
     def setUp(self):
         et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
     <test-entry>
     <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a1"></artifact>
     <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a2"></artifact>
+    <other>thing</other>
     </test-entry>
     """)
         self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
@@ -579,6 +604,15 @@ class TestEntityList(TestCase):
         assert el[0] == a3
         assert el[1] == a4
 
+    def test_clear(self):
+        el = EntityList(self.instance1, 'artifact', Artifact)
+        sd = self._make_desc(StringDescriptor, 'other')
+        assert sd.__get__(self.instance1, None) == "thing"
+        assert len(el) == 2
+        el.clear()
+        assert len(el) == 0
+        assert sd.__get__(self.instance1, None) == "thing"
+
 
 class TestInputOutputMapList(TestCase):
     def setUp(self):
@@ -751,7 +785,7 @@ class TestQueuedArtifactList(TestCase):
                 </location>
                 </artifact>
                 <artifact uri="{url}/artifacts/a3">
-                <queue-time>2011-12-25T01:10:10.050-00:00</queue-time>
+                <queue-time>2011-12-25T01:10:10.050-01:00</queue-time>
                 <location>
                 <container uri="{url}/containers/c1"/>
                 <value>A:3</value>
@@ -783,7 +817,7 @@ class TestQueuedArtifactList(TestCase):
         assert queued_artifacts[0] == qart
         qart = self.get_queue_art('a2', 'A:2', 200000, datetime.timedelta(0, 3600))
         assert queued_artifacts[1] == qart
-        qart = self.get_queue_art('a3', 'A:3', 50000, datetime.timedelta(0, 0))
+        qart = self.get_queue_art('a3', 'A:3', 50000, datetime.timedelta(0, -3600))
         assert queued_artifacts[2] == qart
 
     def test_set(self):

pip install -e .
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
packaging==21.3
pluggy==1.0.0
py==1.11.0
-e git+https://github.com/EdinburghGenomics/pyclarity-lims.git@66586f02da5660a87a4347e246dd76eac0bb29c4#egg=pyclarity_lims
pyparsing==3.1.4
pytest==7.0.1
requests==2.27.1
tomli==1.2.3
typing_extensions==4.1.1
urllib3==1.26.20
zipp==3.6.0

name: pyclarity-lims
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
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - 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=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - requests==2.27.1
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - zipp==3.6.0
prefix: /opt/conda/envs/pyclarity-lims

tests/test_descriptors.py::TestPlacementDictionary::test_clear tests/test_descriptors.py::TestSubTagDictionary::test___setitem__ tests/test_descriptors.py::TestSubTagDictionary::test___setitem__from_empty tests/test_descriptors.py::TestEntityList::test_clear
tests/test_descriptors.py::TestStringDescriptor::test__get__ tests/test_descriptors.py::TestStringDescriptor::test__set__ tests/test_descriptors.py::TestStringDescriptor::test_create tests/test_descriptors.py::TestIntegerDescriptor::test__get__ tests/test_descriptors.py::TestIntegerDescriptor::test__set__ tests/test_descriptors.py::TestIntegerDescriptor::test_create tests/test_descriptors.py::TestBooleanDescriptor::test__get__ tests/test_descriptors.py::TestBooleanDescriptor::test__set__ tests/test_descriptors.py::TestBooleanDescriptor::test_create tests/test_descriptors.py::TestEntityDescriptor::test__get__ tests/test_descriptors.py::TestEntityDescriptor::test__set__ tests/test_descriptors.py::TestEntityDescriptor::test_create tests/test_descriptors.py::TestEntityListDescriptor::test__get__ tests/test_descriptors.py::TestStringAttributeDescriptor::test__get__ tests/test_descriptors.py::TestStringAttributeDescriptor::test__set__ tests/test_descriptors.py::TestStringAttributeDescriptor::test_create tests/test_descriptors.py::TestStringListDescriptor::test__get__ tests/test_descriptors.py::TestStringListDescriptor::test__set__ tests/test_descriptors.py::TestStringDictionaryDescriptor::test__get__ tests/test_descriptors.py::TestStringDictionaryDescriptor::test__set__ tests/test_descriptors.py::TestUdfDictionary::test___delitem__ tests/test_descriptors.py::TestUdfDictionary::test___getitem__ tests/test_descriptors.py::TestUdfDictionary::test___iter__ tests/test_descriptors.py::TestUdfDictionary::test___setitem__ tests/test_descriptors.py::TestUdfDictionary::test___setitem__new tests/test_descriptors.py::TestUdfDictionary::test___setitem__unicode tests/test_descriptors.py::TestUdfDictionary::test_clear tests/test_descriptors.py::TestUdfDictionary::test_create tests/test_descriptors.py::TestUdfDictionary::test_create_with_nesting tests/test_descriptors.py::TestUdfDictionary::test_items tests/test_descriptors.py::TestPlacementDictionary::test___delitem__ tests/test_descriptors.py::TestPlacementDictionary::test___getitem__ tests/test_descriptors.py::TestPlacementDictionary::test___setitem__ tests/test_descriptors.py::TestPlacementDictionary::test___setitem__2 tests/test_descriptors.py::TestSubTagDictionary::test___getitem__ tests/test_descriptors.py::TestXmlElementAttributeDict::test___getitem__ tests/test_descriptors.py::TestXmlElementAttributeDict::test___setitem__ tests/test_descriptors.py::TestXmlElementAttributeDict::test__len__ tests/test_descriptors.py::TestXmlPooledInputDict::test___getitem__ tests/test_descriptors.py::TestXmlPooledInputDict::test___setitem__ tests/test_descriptors.py::TestEntityList::test__get__ tests/test_descriptors.py::TestEntityList::test_append tests/test_descriptors.py::TestEntityList::test_insert tests/test_descriptors.py::TestEntityList::test_set tests/test_descriptors.py::TestEntityList::test_set_list tests/test_descriptors.py::TestInputOutputMapList::test___get__ tests/test_descriptors.py::TestExternalidList::test_append tests/test_descriptors.py::TestExternalidList::test_get tests/test_descriptors.py::TestXmlAttributeList::test_append tests/test_descriptors.py::TestXmlAttributeList::test_get tests/test_descriptors.py::TestXmlAttributeList::test_insert tests/test_descriptors.py::TestXmlReagentLabelList::test_append tests/test_descriptors.py::TestXmlReagentLabelList::test_get tests/test_descriptors.py::TestXmlAction::test_parse tests/test_descriptors.py::TestXmlAction::test_set tests/test_descriptors.py::TestQueuedArtifactList::test_parse tests/test_descriptors.py::TestQueuedArtifactList::test_set
pyclarity_lims/descriptors.py
pyclarity_lims/descriptors.py