8000 spike: rejigger xmlchemy · python-openxml/python-docx@f07823c · GitHub
[go: up one dir, main page]

Skip to content

Commit f07823c

Browse files
committed
spike: rejigger xmlchemy
Metaclasses are different and somewhat better in Python 3. Modernize the `xmlchemy` custom element metaclass mechanism and remove Python 2 work-arounds that are no longer required.
1 parent 5c1b2f0 commit f07823c

File tree

1 file changed

+15
-18
lines changed

1 file changed

+15
-18
lines changed

src/docx/oxml/xmlchemy.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
from __future__ import annotations
44

55
import re
6-
from typing import Any, Callable, List
6+
from typing import Any, Callable, Dict, List, Tuple
77

88
from lxml import etree
99
from lxml.etree import ElementBase
1010

1111
from docx.oxml.exceptions import InvalidXmlError
1212
from docx.oxml.ns import NamespacePrefixedTag, nsmap, qn
13-
from docx.oxml.parser import OxmlElement
1413
from docx.shared import lazyproperty
1514

1615

@@ -84,7 +83,11 @@ def _parse_line(cls, line):
8483
class MetaOxmlElement(type):
8584
"""Metaclass for BaseOxmlElement."""
8685

87-
def __init__(cls, clsname, bases, clsdict):
86+
def __new__(cls, clsname: str, bases: Tuple[type, ...], clsdict: Dict[str, Any]):
87+
bases = (*bases, etree.ElementBase)
88+
return super().__new__(cls, clsname, bases, clsdict)
89+
90+
def __init__(cls, clsname: str, bases: Tuple[type, ...], clsdict: Dict[str, Any]):
8891
dispatchable = (
8992
OneAndOnlyOne,
9093
OneOrMore,
@@ -326,8 +329,8 @@ def _add_to_class(self, name, method):
326329

327330
@property
328331
def _creator(self):
329-
"""Return a function object that creates a new, empty element of the right type,
330-
having no attributes."""
332+
"""Callable that creates an empty element of the right type, with no attrs."""
333+
from docx.oxml.parser import OxmlElement
331334

332335
def new_child_element(obj):
333336
return OxmlElement(self._nsptagname)
@@ -609,21 +612,20 @@ def _remove_choice_group_method_name(self):
609612
return "_remove_%s" % self._prop_name
610613

611614

612-
class _OxmlElementBase(etree.ElementBase):
615+
class BaseOxmlElement(metaclass=MetaOxmlElement):
613616
"""Effective base class for all custom element classes.
614617
615-
Adds standardized behavior to all classes in one place. Actual inheritance is from
616-
BaseOxmlElement below, needed to manage Python 2-3 metaclass declaration
617-
compatibility.
618+
Adds standardized behavior to all classes in one place.
618619
"""
619620

620-
__metaclass__ = MetaOxmlElement
621-
622621
append: Callable[[ElementBase], None]
623622
find: Callable[[str], ElementBase | None]
624623
findall: Callable[[str], List[ElementBase]]
625-
remove: Callable[[ElementBase], None]
624+
getparent: Callable[[], BaseOxmlElement]
625+
insert: Callable[[int, BaseOxmlElement], None]
626+
remove: Callable[[BaseOxmlElement], None]
626627
tag: str
628+
text: str | None
627629

628630
def __repr__(self):
629631
return "<%s '<%s>' at 0x%0x>" % (
@@ -670,13 +672,8 @@ def xpath( # pyright: ignore[reportIncompatibleMethodOverride]
670672
671673
Provides standard Open XML namespace mapping (`nsmap`) in centralized location.
672674
"""
673-
return super(BaseOxmlElement, self).xpath(xpath_str, namespaces=nsmap)
675+
return super().xpath(xpath_str, namespaces=nsmap)
674676

675677
@property
676678
def _nsptag(self) -> str:
677679
return NamespacePrefixedTag.from_clark_name(self.tag)
678-
679-
680-
BaseOxmlElement = MetaOxmlElement(
681-
"BaseOxmlElement", (etree.ElementBase,), dict(_OxmlElementBase.__dict__)
682-
)

0 commit comments

Comments
 (0)
0