Exemple #1
0
    def parse_kwargs(self, kwargs, name, available_kwargs):
        if self.accepts_multiple:
            if name not in kwargs:
                return {}

            available_kwargs.remove(name)
            item_kwargs = kwargs[name]

            result = []
            sub_name = "_value_1" if self.child.accepts_multiple else None
            for sub_kwargs in max_occurs_iter(self.max_occurs, item_kwargs):
                available_sub_kwargs = set(sub_kwargs.keys())
                subresult = self.child.parse_kwargs(sub_kwargs, sub_name,
                                                    available_sub_kwargs)

                if available_sub_kwargs:
                    raise TypeError(
                        ("%s() got an unexpected keyword argument %r.") %
                        (self, list(available_sub_kwargs)[0]))

                if subresult:
                    result.append(subresult)
            if result:
                result = {name: result}
        else:
            result = self.child.parse_kwargs(kwargs, name, available_kwargs)
        return result
Exemple #2
0
    def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
        """Consume matching xmlelements

        :param xmlelements: Dequeue of XML element objects
        :type xmlelements: collections.deque of lxml.etree._Element
        :param schema: The parent XML schema
        :type schema: zeep.xsd.Schema
        :param name: The name of the parent element
        :type name: str
        :param context: Optional parsing context (for inline schemas)
        :type context: zeep.xsd.context.XmlParserContext
        :rtype: dict or None

        """
        result = []

        for _unused in max_occurs_iter(self.max_occurs):
            result.append(
                self.child.parse_xmlelements(xmlelements,
                                             schema,
                                             name,
                                             context=context))
            if not xmlelements:
                break
        if not self.accepts_multiple and result:
            return result[0]
        return {name: result}
Exemple #3
0
    def render(self, parent, value, render_path):
        """Create subelements in the given parent object."""
        if not isinstance(value, list):
            values = [value]
        else:
            values = value

        self.validate(values, render_path)

        for value in max_occurs_iter(self.max_occurs, values):
            for name, element in self.elements_nested:
                if name:
                    if name in value:
                        element_value = value[name]
                        child_path = render_path + [name]
                    else:
                        element_value = NotSet
                        child_path = render_path
                else:
                    element_value = value
                    child_path = render_path

                if element_value is SkipValue:
                    continue

                if element_value is not None or not element.is_optional:
                    element.render(parent, element_value, child_path)
Exemple #4
0
    def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
        """Consume matching xmlelements and call parse() on each of them

        :param xmlelements: Dequeue of XML element objects
        :type xmlelements: collections.deque of lxml.etree._Element
        :param schema: The parent XML schema
        :type schema: zeep.xsd.Schema
        :param name: The name of the parent element
        :type name: str
        :param context: Optional parsing context (for inline schemas)
        :type context: zeep.xsd.context.XmlParserContext
        :return: dict or None

        """
        result = []

        for _unused in max_occurs_iter(self.max_occurs):
            if xmlelements:
                xmlelement = xmlelements.popleft()
                item = self.parse(xmlelement, schema, context=context)
                if item is not None:
                    result.append(item)
            else:
                break

        if not self.accepts_multiple:
            result = result[0] if result else None
        return result
Exemple #5
0
    def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
        """Consume matching xmlelements

        :param xmlelements: Dequeue of XML element objects
        :type xmlelements: collections.deque of lxml.etree._Element
        :param schema: The parent XML schema
        :type schema: zeep.xsd.Schema
        :param name: The name of the parent element
        :type name: str
        :param context: Optional parsing context (for inline schemas)
        :type context: zeep.xsd.context.XmlParserContext
        :rtype: dict or None

        """
        result = []

        if self.accepts_multiple:
            assert name

        for _unused in max_occurs_iter(self.max_occurs):
            if not xmlelements:
                break

            item_result = OrderedDict()
            for elm_name, element in self.elements:
                try:
                    item_subresult = element.parse_xmlelements(xmlelements,
                                                               schema,
                                                               name,
                                                               context=context)
                except UnexpectedElementError:
                    if schema.settings.strict:
                        raise
                    item_subresult = None

                # Unwrap if allowed
                if isinstance(element, OrderIndicator):
                    item_result.update(item_subresult)
                else:
                    item_result[elm_name] = item_subresult

                if not xmlelements:
                    break
            if item_result:
                result.append(item_result)

        if not self.accepts_multiple:
            return result[0] if result else None
        return {name: result}
Exemple #6
0
    def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
        """Consume matching xmlelements and call parse() on each of them

        :param xmlelements: Dequeue of XML element objects
        :type xmlelements: collections.deque of lxml.etree._Element
        :param schema: The parent XML schema
        :type schema: zeep.xsd.Schema
        :param name: The name of the parent element
        :type name: str
        :param context: Optional parsing context (for inline schemas)
        :type context: zeep.xsd.context.XmlParserContext
        :return: dict or None

        """
        result = []
        num_matches = 0
        for _unused in max_occurs_iter(self.max_occurs):
            if not xmlelements:
                break

            # Workaround for SOAP servers which incorrectly use unqualified
            # or qualified elements in the responses (#170, #176). To make the
            # best of it we compare the full uri's if both elements have a
            # namespace. If only one has a namespace then only compare the
            # localname.

            # If both elements have a namespace and they don't match then skip
            element_tag = etree.QName(xmlelements[0].tag)
            if (element_tag.namespace and self.qname.namespace
                    and element_tag.namespace != self.qname.namespace
                    and schema.settings.strict):
                break

            # Only compare the localname
            if element_tag.localname == self.qname.localname:
                xmlelement = xmlelements.popleft()
                num_matches += 1
                item = self.parse(xmlelement,
                                  schema,
                                  allow_none=True,
                                  context=context)
                result.append(item)
            elif (schema is not None
                  and schema.settings.xsd_ignore_sequence_order and list(
                      filter(
                          lambda elem: etree.QName(elem.tag).localname == self.
                          qname.localname,
                          xmlelements,
                      ))):
                # Search for the field in remaining elements, not only the leftmost
                xmlelement = list(
                    filter(
                        lambda elem: etree.QName(elem.tag).localname == self.
                        qname.localname,
                        xmlelements,
                    ))[0]
                xmlelements.remove(xmlelement)
                num_matches += 1
                item = self.parse(xmlelement,
                                  schema,
                                  allow_none=True,
                                  context=context)
                result.append(item)
            else:
                # If the element passed doesn't match and the current one is
                # not optional then throw an error
                if num_matches == 0 and not self.is_optional:
                    raise UnexpectedElementError(
                        "Unexpected element %r, expected %r" %
                        (element_tag.text, self.qname.text))
                break

        if not self.accepts_multiple:
            result = result[0] if result else None
        return result
Exemple #7
0
    def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
        """Consume matching xmlelements

        :param xmlelements: Dequeue of XML element objects
        :type xmlelements: collections.deque of lxml.etree._Element
        :param schema: The parent XML schema
        :type schema: zeep.xsd.Schema
        :param name: The name of the parent element
        :type name: str
        :param context: Optional parsing context (for inline schemas)
        :type context: zeep.xsd.context.XmlParserContext
        :rtype: dict or None

        """
        result = []

        for _unused in max_occurs_iter(self.max_occurs):
            if not xmlelements:
                break

            # Choose out of multiple
            options = []
            for element_name, element in self.elements_nested:

                local_xmlelements = copy.copy(xmlelements)

                try:
                    sub_result = element.parse_xmlelements(
                        xmlelements=local_xmlelements,
                        schema=schema,
                        name=element_name,
                        context=context,
                    )
                except UnexpectedElementError:
                    continue

                if isinstance(element, Element):
                    sub_result = {element_name: sub_result}

                num_consumed = len(xmlelements) - len(local_xmlelements)
                if num_consumed:
                    options.append((num_consumed, sub_result))

            if not options:
                xmlelements = []
                break

            # Sort on least left
            options = sorted(options, key=operator.itemgetter(0), reverse=True)
            if options:
                result.append(options[0][1])
                for i in range(options[0][0]):
                    xmlelements.popleft()
            else:
                break

        if self.accepts_multiple:
            result = {name: result}
        else:
            result = result[0] if result else {}
        return result
Exemple #8
0
    def parse_kwargs(self, kwargs, name, available_kwargs):
        """Apply the given kwarg to the element.

        The available_kwargs is modified in-place. Returns a dict with the
        result.

        :param kwargs: The kwargs
        :type kwargs: dict
        :param name: The name as which this type is registered in the parent
        :type name: str
        :param available_kwargs: The kwargs keys which are still available,
         modified in place
        :type available_kwargs: set
        :rtype: dict

        """
        if self.accepts_multiple:
            assert name

        if name:
            if name not in available_kwargs:
                return {}

            assert self.accepts_multiple

            # Make sure we have a list, lame lame
            item_kwargs = kwargs.get(name)
            if not isinstance(item_kwargs, list):
                item_kwargs = [item_kwargs]

            result = []
            for item_value in max_occurs_iter(self.max_occurs, item_kwargs):
                try:
                    item_kwargs = set(item_value.keys())
                except AttributeError:
                    raise TypeError(
                        "A list of dicts is expected for unbounded Sequences")

                subresult = OrderedDict()
                for item_name, element in self.elements:
                    value = element.parse_kwargs(item_value, item_name,
                                                 item_kwargs)
                    if value is not None:
                        subresult.update(value)

                if item_kwargs:
                    raise TypeError(
                        ("%s() got an unexpected keyword argument %r.") %
                        (self, list(item_kwargs)[0]))

                result.append(subresult)

            result = {name: result}

            # All items consumed
            if not any(filter(None, item_kwargs)):
                available_kwargs.remove(name)

            return result

        else:
            assert not self.accepts_multiple
            result = OrderedDict()
            for elm_name, element in self.elements_nested:
                sub_result = element.parse_kwargs(kwargs, elm_name,
                                                  available_kwargs)
                if sub_result:
                    result.update(sub_result)

            return result