Skip to content

Commit

Permalink
feat: to_etree_element (#201)
Browse files Browse the repository at this point in the history
* feat: to_etree_element

* add test

* quote the type hint
  • Loading branch information
tlambert03 authored Jul 12, 2023
1 parent 6d77db6 commit 7f144fa
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/xsdata_pydantic_basemodel/compat.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
try:
from lxml import etree as ET
except ImportError:
import xml.etree.ElementTree as ET # type: ignore

from dataclasses import MISSING, field
from typing import (
Any,
Expand All @@ -11,7 +16,6 @@
TypeVar,
cast,
)
from xml.etree.ElementTree import QName

from pydantic import BaseModel, validators
from pydantic.fields import Field, ModelField, Undefined
Expand Down Expand Up @@ -45,6 +49,14 @@ class AnyElement(BaseModel):
class Config:
arbitrary_types_allowed = True

def to_etree_element(self) -> "ET._Element":
elem = ET.Element(self.qname or "", self.attributes)
elem.text = self.text
elem.tail = self.tail
for child in self.children:
elem.append(child.to_etree_element())
return elem


class DerivedElement(BaseModel, Generic[T]):
"""Generic model wrapper for type substituted elements.
Expand Down Expand Up @@ -136,7 +148,7 @@ def validator(value: Any) -> Any:
(XmlTime, make_validators(XmlTime, XmlTime.from_string)),
(XmlDuration, make_validators(XmlDuration, XmlDuration)),
(XmlPeriod, make_validators(XmlPeriod, XmlPeriod)),
(QName, make_validators(QName, QName)),
(ET.QName, make_validators(ET.QName, ET.QName)),
]
)
else:
Expand Down
13 changes: 13 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
ALL_XML = set(DATA.glob("*.ome.xml"))
INVALID = {DATA / "invalid_xml_annotation.ome.xml", DATA / "bad.ome.xml"}
OLD_SCHEMA = {DATA / "seq0000xy01c1.ome.xml", DATA / "2008_instrument.ome.xml"}
WITH_XML_ANNOTATIONS = {
DATA / "ome_ns.ome.xml",
DATA / "OverViewScan.ome.xml",
DATA / "spim.ome.xml",
DATA / "xmlannotation-svg.ome.xml",
DATA / "xmlannotation-multi-value.ome.xml",
DATA / "xmlannotation-body-space.ome.xml",
}


def _true_stem(p: Path) -> str:
Expand All @@ -39,6 +47,11 @@ def invalid_xml(request: pytest.FixtureRequest) -> Path:
return request.param


@pytest.fixture(params=sorted(WITH_XML_ANNOTATIONS), ids=_true_stem)
def with_xml_annotations(request: pytest.FixtureRequest) -> Path:
return request.param


@pytest.fixture
def single_xml() -> Path:
return DATA / "example.ome.xml"
Expand Down
16 changes: 16 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,22 @@ def test_numpy_pixel_types() -> None:
numpy.dtype(m.numpy_dtype)


def test_xml_annotations_to_etree(with_xml_annotations: Path) -> None:
from xsdata_pydantic_basemodel.compat import AnyElement

try:
from lxml.etree import _Element as Elem
except ImportError:
from xml.etree.ElementTree import Element as Elem # type: ignore

ome = from_xml(with_xml_annotations)
for anno in ome.structured_annotations:
if isinstance(anno, model.XMLAnnotation):
for elem in anno.value.any_elements:
assert isinstance(elem, AnyElement)
assert isinstance(elem.to_etree_element(), Elem)


def test_update_unset(pixels: model.Pixels) -> None:
"""Make sure objects appended to mutable sequences are included in the xml."""
ome = model.OME()
Expand Down

0 comments on commit 7f144fa

Please sign in to comment.