Skip to content

Commit

Permalink
Fix/v1 ext extension (#250)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the title above -->
<!--- Link the corresponding issues after you created the pull request
-->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
- [x] I have updated the [changelog](../CHANGELOG.md) accordingly.
- [x] I have added tests to cover my changes.
  • Loading branch information
deichmab-draeger authored Sep 5, 2023
1 parent c1118d6 commit 15f065b
Show file tree
Hide file tree
Showing 5 changed files with 393 additions and 104 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- fixed a bug where coping a xml node would not work if namespace have been defined multiple time [#232](https://github.com/Draegerwerk/sdc11073/issues/232)
- getContextState sets correct BindingVersion [#168](https://github.com/Draegerwerk/sdc11073/issues/168).
- comparison of extensions would fail, ExtensionLocalValue type added

### Changed

Expand Down
97 changes: 75 additions & 22 deletions src/sdc11073/mdib/containerproperties.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from sdc11073 import isoduration
from sdc11073.dataconverters import TimestampConverter, DecimalConverter, IntegerConverter, BooleanConverter, \
DurationConverter, NullConverter
from sdc11073.xmlparsing import copy_node_wo_parent


class ElementNotFoundException(Exception):
Expand Down Expand Up @@ -456,45 +457,97 @@ def updateXMLValue(self, instance, node):
subNode.text = value


def _compare_extension(left: etree_.ElementBase, right: etree_.ElementBase) -> bool:
# xml comparison
try:
if left.tag != right.tag: # compare expanded names
return False
if dict(left.attrib) != dict(right.attrib): # unclear how lxml _Attrib compares
return False
except AttributeError: # right side is not an Element type because expected attributes are missing
return False

# ignore comments
left_children = [child for child in left if not isinstance(child, etree_._Comment)]
right_children = [child for child in right if not isinstance(child, etree_._Comment)]

if len(left_children) != len(right_children): # compare children count
return False
if len(left_children) == 0 and len(right_children) == 0:
if left.text != right.text: # mixed content is not allowed. only compare text if there are no children
return False

return all(map(_compare_extension, left_children, right_children)) # compare children but keep order


class ExtensionLocalValue(list):

compare_method = _compare_extension
"""may be overwritten by user if a custom comparison behaviour is required"""

def __eq__(self, other):
try:
if len(self) != len(other):
return False
except TypeError: # len of other cannot be determined
return False
return all(self.__class__.compare_method(left, right) for left, right in zip(self, other))


class ExtensionNodeProperty(_PropertyBase):
""" Represents an ext:Extension Element that contains xml tree of any kind."""
"""Represents an ext:Extension Element that contains 0...n child elements of any kind.
The python representation is an ExtensionLocalValue with list of elements.
"""

def __init__(self, subElementNames=None, defaultPyValue=None):
if subElementNames is None:
subElementNames = [namespaces.extTag('Extension')]
else:
subElementNames.append(namespaces.extTag('Extension'))
attrname = '_ext_ext'
super(ExtensionNodeProperty, self).__init__(attrname, subElementNames, defaultPyValue)
super().__init__(attrname, subElementNames, defaultPyValue)
self._converter = None

def __set__(self, instance, pyValue):
if not isinstance(pyValue, ExtensionLocalValue):
pyValue = ExtensionLocalValue(pyValue)
super().__set__(instance, pyValue)

def __get__(self, instance, owner):
"""Return a python value, uses the locally stored value."""
if instance is None: # if called via class
return self
try:
value = getattr(instance, self._localVarName)
except AttributeError:
value = None
if value is None:
value = _PropertyValue(None, ExtensionLocalValue())
setattr(instance, self._localVarName, value)
return value.py_value

def getPyValueFromNode(self, node):
"""Read value from node."""
try:
subNode = self._getElementbyChildNamesList(node, self._subElementNames, createMissingNodes=False)
return _PropertyValue(None, subNode) # subNode is the ext:Extension node
extension_node = self._getElementbyChildNamesList(node, self._subElementNames, createMissingNodes=False)
except ElementNotFoundException:
return None
return _PropertyValue(None, ExtensionLocalValue())
return _PropertyValue(extension_node, ExtensionLocalValue(extension_node[:]))

def updateXMLValue(self, instance, node):
"""Write value to node.
The Extension Element is only added if there is at least one element available in local list.
"""
try:
property_value = getattr(instance, self._localVarName)
except AttributeError: # set to None (it is in the responsibility of the called method to do the right thing)
property_value = None
if property_value is None:
try:
parentNode = self._getElementbyChildNamesList(node, self._subElementNames[:-1],
createMissingNodes=False)
except ElementNotFoundException:
return
subNode = parentNode.find(self._subElementNames[-1])
if subNode is not None:
parentNode.remove(subNode)
else:
subNode = self._getElementbyChildNamesList(node, self._subElementNames, createMissingNodes=True)

del subNode[:] # delete all children first
if property_value.py_value is not None:
subNode.extend([copy.copy(n) for n in property_value.py_value])
except AttributeError:
return # nothing to add
if property_value is None or len(property_value.py_value) == 0:
return # nothing to add
sub_node = self._getElementbyChildNamesList(node, self._subElementNames, createMissingNodes=True)
sub_node.extend(copy_node_wo_parent(x) for x in property_value.py_value)


class SubElementProperty(_PropertyBase):
Expand Down
Loading

0 comments on commit 15f065b

Please sign in to comment.