Source code for miniopy_async.xml

# -*- coding: utf-8 -*-
# Asynchronous MinIO Client SDK for Python
# (C) 2020 MinIO, Inc.
# (C) 2022 Huseyn Mashadiyev <mashadiyev.huseyn@gmail.com>
# (C) 2022 L-ING <hlf01@icloud.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""XML utility module."""

from __future__ import absolute_import, annotations

import io
from typing import Protocol, Type, TypeVar
from xml.etree import ElementTree as ET

_S3_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/"


[docs] def Element( tag: str, namespace: str = _S3_NAMESPACE, ) -> ET.Element: # pylint: disable=invalid-name """Create ElementTree.Element with tag and namespace.""" return ET.Element(tag, {"xmlns": namespace} if namespace else {})
[docs] def SubElement( # pylint: disable=invalid-name parent: ET.Element, tag: str, text: str | None = None ) -> ET.Element: """Create ElementTree.SubElement on parent with tag and text.""" element = ET.SubElement(parent, tag) if text is not None: element.text = text return element
def _get_namespace(element: ET.Element) -> str: """Exact namespace if found.""" start = element.tag.find("{") if start < 0: return "" start += 1 end = element.tag.find("}") if end < 0: return "" return element.tag[start:end]
[docs] def findall(element: ET.Element, name: str) -> list[ET.Element]: """Namespace aware ElementTree.Element.findall().""" namespace = _get_namespace(element) if namespace: name = "/".join(["ns:" + token for token in name.split("/")]) return element.findall(name, {"ns": namespace} if namespace else {})
[docs] def find( element: ET.Element, name: str, strict: bool = False, ) -> ET.Element | None: """Namespace aware ElementTree.Element.find().""" namespace = _get_namespace(element) elem = element.find( "ns:" + name if namespace else name, {"ns": namespace} if namespace else {}, ) if strict and elem is None: raise ValueError(f"XML element <{name}> not found") return elem
[docs] def findtext( element: ET.Element, name: str, strict: bool = False, ) -> str | None: """ Namespace aware ElementTree.Element.findtext() with strict flag raises ValueError if element name not exist. """ elem = find(element, name, strict=strict) return None if elem is None else (elem.text or "")
A = TypeVar("A")
[docs] class FromXmlType(Protocol): """typing stub for class with `fromxml` method"""
[docs] @classmethod def fromxml(cls: Type[A], element: ET.Element) -> A: """Create python object with values from XML element.""" ...
B = TypeVar("B", bound=FromXmlType)
[docs] def unmarshal(cls: Type[B], xmlstring: str) -> B: """Unmarshal given XML string to an object of passed class.""" return cls.fromxml(ET.fromstring(xmlstring))
[docs] def getbytes(element: ET.Element) -> bytes: """Convert ElementTree.Element to bytes.""" with io.BytesIO() as data: ET.ElementTree(element).write( data, encoding=None, xml_declaration=False, ) return data.getvalue()
[docs] class ToXmlType(Protocol): """typing stub for class with `toxml` method"""
[docs] def toxml(self, element: ET.Element | None) -> ET.Element: """Convert python object to ElementTree.Element.""" ...
[docs] def marshal(obj: ToXmlType) -> bytes: """Get XML data as bytes of ElementTree.Element.""" return getbytes(obj.toxml(None))