Is it possible to wrap a function of an instance of a built-in class, i.e. add functionality to an already created instance of a built-in class? As a concrete example, when parsing xml files using ElementTree, the Element.find
method returns an Element or None, depending on if the Element can be found. However, I would like to raise a KeyError, every time an Element cannot be found, instead of returning None. Applying the solution below (found here), leads to an TypeError: __class__ assignment only supported for heap types or ModuleType subclasses
. When trying to monkeypatch the function (not my preferred solution, as the KeyError raising Element shouldn't persist globally, but would be better than nothing), also produces a TypeError: TypeError: can't set attributes of built-in/extension type 'xml.etree.ElementTree.Element'
. Is updating an instance with additional class functionality not possible, or am I completely over thinking the problem and there is a way simpler solution?
from typing import Any, Dict, Optional, Text, Union
from xml.etree import ElementTree as et
_str_argument_type = Union[str, Text]
class StrictElement(et.Element):
@classmethod
def from_element(cls, element: et.Element) -> "StrictElement":
assert isinstance(element, et.Element)
element.__class__ = cls
assert isinstance(element, StrictElement)
return element
@staticmethod
def find(
path: _str_argument_type,
namespaces: Optional[Dict[_str_argument_type, _str_argument_type]] = ...,
) -> "StrictElement":
element = super().find(path, namespaces)
if element is None:
raise KeyError(f"unable to find element {path}")
return StrictElement.from_element(element)
foo = et.parse("some_path") # some xml file with foo element but not foobar element
strict_foo = StrictElement.from_element(foo)
other_strict_foo = strict_foo.find("bar")
strict_foo.find("foobar") # should raise key error and not return None if element isn't found