Python: Inject attribute into object created by C library

466 views Asked by At

I'm trying to inject an attribute into lxml.etree._Element, but as that module is completely implemented in C, setattr fails:

Traceback (most recent call last):
[...]
    setattr(node.getroottree().getroot(), "attributeName", value)
AttributeError: 'lxml.etree._Element' object has no attribute 'attributeName'

The use case: I have a function that extracts text from a XML file by XPath and replaces $(ENV)-like matches by the corresponding value. Therefore I don't want to have to pass the variables dictionary (e.g. {"ENV" : "replacement"} to that function each time. Instead it would be easier to just have an attribute at a fixed place (XML root in my code). I could do a dumb workaround but injecting a Python attribute would be the best way. I cannot use a global variable because each XML file can have different variable values.

So, any way to inject something into C-based classes/objects?

1

There are 1 answers

3
ncoghlan On BEST ANSWER

You generally can't, as instances of C-defined types typically don't have per-instance __dict__ entries to hold arbitrary attributes.

A workaround for cases when a subclass or wrapper class won't work is to create a helper dictionary at the module level that maps the object you have to additional information. If the object you have isn't hashable, you can use id(obj) instead.

So, for example, you could store a dictionary associated with the id of each root object:

# Module level, setting up the data store
from collections import defaultdict
extra_info = defaultdict(dict) # Creates empty dicts for unknown keys

# Saving the info
root = node.getroottree().getroot()
extra_info[id(root)]["ENV"] = "replacement"

# Retrieving it later
root = node.getroottree().getroot()
info = extra_info[id(root)]