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