-
Notifications
You must be signed in to change notification settings - Fork 319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add type annotations to xml.py #1327
Changes from 5 commits
519e508
5dd80fa
0b72d4d
3e47c5b
1518522
3f9c626
e56d5cb
54d4de1
c52846c
3164520
2848f7e
a9e00d6
ea451b6
4a58992
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,17 +16,19 @@ | |
|
||
"""XML utility module.""" | ||
|
||
from __future__ import absolute_import | ||
|
||
from __future__ import absolute_import, annotations | ||
from typing import Type, TypeVar | ||
import io | ||
from xml.etree import ElementTree as ET | ||
|
||
from typing_extensions import Protocol | ||
|
||
_S3_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/" | ||
|
||
|
||
def Element(tag, namespace=_S3_NAMESPACE): # pylint: disable=invalid-name | ||
def Element(tag: str, namespace=_S3_NAMESPACE): # pylint: disable=invalid-name | ||
"""Create ElementTree.Element with tag and namespace.""" | ||
return ET.Element(tag, {'xmlns': namespace} if namespace else {}) | ||
return ET.Element(tag, {"xmlns": namespace} if namespace else {}) | ||
|
||
|
||
def SubElement(parent, tag, text=None): # pylint: disable=invalid-name | ||
|
@@ -37,7 +39,7 @@ def SubElement(parent, tag, text=None): # pylint: disable=invalid-name | |
return element | ||
|
||
|
||
def _get_namespace(element): | ||
def _get_namespace(element: ET.Element): | ||
"""Exact namespace if found.""" | ||
start = element.tag.find("{") | ||
if start < 0: | ||
|
@@ -49,7 +51,7 @@ def _get_namespace(element): | |
return element.tag[start:end] | ||
|
||
|
||
def findall(element, name): | ||
def findall(element: ET.Element, name: str) -> list[ET.Element]: | ||
"""Namespace aware ElementTree.Element.findall().""" | ||
namespace = _get_namespace(element) | ||
return element.findall( | ||
|
@@ -58,7 +60,7 @@ def findall(element, name): | |
) | ||
|
||
|
||
def find(element, name): | ||
def find(element: ET.Element, name: str): | ||
"""Namespace aware ElementTree.Element.find().""" | ||
namespace = _get_namespace(element) | ||
return element.find( | ||
|
@@ -67,7 +69,11 @@ def find(element, name): | |
) | ||
|
||
|
||
def findtext(element, name, strict=False): | ||
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. | ||
|
@@ -80,20 +86,43 @@ def findtext(element, name, strict=False): | |
return element.text or "" | ||
|
||
|
||
def unmarshal(cls, xmlstring): | ||
K = TypeVar("K") | ||
|
||
|
||
class IFromXML(Protocol): | ||
trim21 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""typing stub for class with `fromxml` method""" | ||
|
||
@classmethod | ||
def fromxml(cls: Type[K], element: ET.Element) -> K: | ||
"""Create python object with values from XML element.""" | ||
|
||
|
||
T = TypeVar("T", bound=IFromXML) | ||
harshavardhana marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
def unmarshal(cls: Type[T], xmlstring: str) -> T: | ||
"""Unmarshal given XML string to an object of passed class.""" | ||
return cls.fromxml(ET.fromstring(xmlstring)) | ||
|
||
|
||
def getbytes(element): | ||
def getbytes(element: ET.Element) -> bytes: | ||
"""Convert ElementTree.Element to bytes.""" | ||
data = io.BytesIO() | ||
ET.ElementTree(element).write( | ||
data, encoding=None, xml_declaration=False, | ||
) | ||
return data.getvalue() | ||
with io.BytesIO() as data: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. close file and discard the buffer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not necessary, gc will handle them if we don't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep. For this function, it is unnecessary. |
||
ET.ElementTree(element).write( | ||
data, | ||
encoding=None, | ||
xml_declaration=False, | ||
) | ||
return data.getvalue() | ||
|
||
|
||
class IToXML(Protocol): | ||
balamurugana marked this conversation as resolved.
Show resolved
Hide resolved
trim21 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""typing stub for class with `toxml` method""" | ||
|
||
def toxml(self, element: ET.Element | None) -> ET.Element: | ||
"""Convert python object to ElementTree.Element.""" | ||
|
||
|
||
def marshal(obj): | ||
def marshal(obj: IToXML) -> bytes: | ||
"""Get XML data as bytes of ElementTree.Element.""" | ||
return getbytes(obj.toxml(None)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have meaningful name here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is generic type parameter, it's custom to be named as
T
K
J
。it's likei
x
,y
in looping.