commit 666ffd8a6cfbc205d1d32e69a2663d9923f487f8 Author: Michael Simacek msimacek@redhat.com Date: Thu Feb 19 15:15:53 2015 +0100
Implement our custom xml binding replacement
python/javapackages/common/binding.py | 178 +++++++++++++++++++++++++++++++++ 1 files changed, 178 insertions(+), 0 deletions(-) --- diff --git a/python/javapackages/common/binding.py b/python/javapackages/common/binding.py new file mode 100644 index 0000000..d0de116 --- /dev/null +++ b/python/javapackages/common/binding.py @@ -0,0 +1,178 @@ +#- +# Copyright (c) 2015, Red Hat, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Red Hat nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Michael Simacek msimacek@redhat.com + +import six + +from lxml import etree +from copy import deepcopy + +def _get_item_type(spec): + assert 0 < len(spec) <= 2, spec + spec = tuple(spec) + ret = spec[0] + if len(spec) == 1: + if isinstance(spec[0], six.string_types): + ret = str + elif isinstance(spec[0], six.string_types): + ret = spec[1] + assert isinstance(ret, type), ret + return ret + +def _get_item_name(spec): + assert 0 < len(spec) <= 2, spec + spec = tuple(spec) + ret = spec[0] + if isinstance(spec[0], type) and issubclass(spec[0], ObjectBinding): + ret = spec[0].element_name + elif len(spec) == 2 and isinstance(spec[0], type): + ret = spec[1] + assert isinstance(ret, six.string_types), ret + return ret + +def from_element(for_type, element): + if for_type is str: + return element.text.strip() if element.text is not None else None + if isinstance(for_type, list): + item_type = _get_item_type(for_type) + return [from_element(item_type, child) for child in element + if etree.iselement(child)] + if isinstance(for_type, set): + item_type = _get_item_type(for_type) + return set([from_element(item_type, child) for child in element + if etree.iselement(child)]) + if for_type is dict: + new = {} + for child in element: + if isinstance(child.tag, six.string_types): + name = etree.QName(child.tag).localname + value = from_element(str, child) + new[name] = value + return new + if isinstance(for_type, type) and issubclass(for_type, ObjectBinding): + new = {} + for child in element: + if isinstance(child.tag, six.string_types): + name = etree.QName(child.tag).localname + if name in for_type.fields: + value = from_element(for_type.types.get(name, str), child) + new[name] = value + return for_type(**new) + raise TypeError("Unrecognized binding type: {0}".format(for_type)) + + +def to_element(obj, name=None, type_spec=None): + if isinstance(obj, six.string_types): + element = etree.Element(name) + element.text = obj + return element + if isinstance(obj, list) or isinstance(obj, set): + element = etree.Element(name) + for item in obj: + element.append(to_element(item, name=_get_item_name(type_spec))) + return element + if isinstance(obj, dict): + element = etree.Element(name) + for key, value in obj.items(): + entry = etree.Element(key) + entry.text = value + element.append(entry) + return element + if isinstance(obj, ObjectBinding): + name = obj.element_name + if obj.namespace: + name = '{' + obj.namespace + '}' + obj.element_name + element = etree.Element(name) + for item_name in obj.fields: + value = obj.values.get(item_name) + if value and value != obj.defaults.get(item_name): + child = to_element(value, item_name, obj.types.get(item_name, str)) + element.append(child) + return element + +class ObjectBinding(object): + element_name = None + fields = [] + defaults = {} + types = {} + equality = None + namespace = None + + def __init__(self, *args, **kwargs): + assert self.element_name + assert self.fields + self.values = self.defaults.copy() + for name, item_type in self.types.items(): + if name not in self.values: + if type(item_type) in (list, set): + self.values[name] = type(item_type)() + elif item_type == dict: + self.values[name] = {} + else: + self.values[name] = None + values = zip(self.fields, args) + kwargs.items() + for name, value in values: + setattr(self, name, value) + + def __getattr__(self, name): + if name in self.fields: + return self.values.get(name, self.defaults.get(name)) + return getattr(super(ObjectBinding, self), name) + + def __setattr__(self, name, value): + if name in self.fields: + self.values[name] = value + else: + super(ObjectBinding, self).__setattr__(name, value) + + def __repr__(self): + return repr(self.values) + + def _get_values_for_equality(self): + if self.equality is not None: + return [v for k, v in self.values.items() if k in self.equality] + return [v for k, v in self.values.items()] + + def __eq__(self, that): + return self is that or (type(self) is type(that) and + self._get_values_for_equality() + == that._get_values_for_equality()) + + def __ne__(self, that): + return not self.__eq__(that) + + def __hash__(self): + if self.equality: + return hash(self._get_values_for_equality) + return id(self) + + def copy(self): + return deepcopy(self)
java-sig-commits@lists.fedoraproject.org