|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | 5 | import re |
6 | | -from typing import Any, Callable, List |
| 6 | +from typing import Any, Callable, Dict, List, Tuple |
7 | 7 |
|
8 | 8 | from lxml import etree |
9 | 9 | from lxml.etree import ElementBase |
10 | 10 |
|
11 | 11 | from docx.oxml.exceptions import InvalidXmlError |
12 | 12 | from docx.oxml.ns import NamespacePrefixedTag, nsmap, qn |
13 | | -from docx.oxml.parser import OxmlElement |
14 | 13 | from docx.shared import lazyproperty |
15 | 14 |
|
16 | 15 |
|
@@ -84,7 +83,11 @@ def _parse_line(cls, line): |
84 | 83 | class MetaOxmlElement(type): |
85 | 84 | """Metaclass for BaseOxmlElement.""" |
86 | 85 |
|
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]): |
88 | 91 | dispatchable = ( |
89 | 92 | OneAndOnlyOne, |
90 | 93 | OneOrMore, |
@@ -326,8 +329,8 @@ def _add_to_class(self, name, method): |
326 | 329 |
|
327 | 330 | @property |
328 | 331 | 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 |
331 | 334 |
|
332 | 335 | def new_child_element(obj): |
333 | 336 | return OxmlElement(self._nsptagname) |
@@ -609,21 +612,20 @@ def _remove_choice_group_method_name(self): |
609 | 612 | return "_remove_%s" % self._prop_name |
610 | 613 |
|
611 | 614 |
|
612 | | -class _OxmlElementBase(etree.ElementBase): |
| 615 | +class BaseOxmlElement(metaclass=MetaOxmlElement): |
613 | 616 | """Effective base class for all custom element classes. |
614 | 617 |
|
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. |
618 | 619 | """ |
619 | 620 |
|
620 | | - __metaclass__ = MetaOxmlElement |
621 | | - |
622 | 621 | append: Callable[[ElementBase], None] |
623 | 622 | find: Callable[[str], ElementBase | None] |
624 | 623 | 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] |
626 | 627 | tag: str |
| 628 | + text: str | None |
627 | 629 |
|
628 | 630 | def __repr__(self): |
629 | 631 | return "<%s '<%s>' at 0x%0x>" % ( |
@@ -670,13 +672,8 @@ def xpath( # pyright: ignore[reportIncompatibleMethodOverride] |
670 | 672 |
|
671 | 673 | Provides standard Open XML namespace mapping (`nsmap`) in centralized location. |
672 | 674 | """ |
673 | | - return super(BaseOxmlElement, self).xpath(xpath_str, namespaces=nsmap) |
| 675 | + return super().xpath(xpath_str, namespaces=nsmap) |
674 | 676 |
|
675 | 677 | @property |
676 | 678 | def _nsptag(self) -> str: |
677 | 679 | return NamespacePrefixedTag.from_clark_name(self.tag) |
678 | | - |
679 | | - |
680 | | -BaseOxmlElement = MetaOxmlElement( |
681 | | - "BaseOxmlElement", (etree.ElementBase,), dict(_OxmlElementBase.__dict__) |
682 | | -) |
0 commit comments