Closed VietThan closed 1 year ago
Hello,
you're on the right track! I've modified your example to this:
# example.py
from __future__ import annotations
from typing import Any
from attrs import define
from cattr.gen import make_dict_structure_fn, override
from cattr.preconf.json import make_converter
@define
class Ns2LogTransaction:
_xmlns_ns2: str
"""@xmlns:ns2"""
@define
class SBody:
ns2_logTransaction: Ns2LogTransaction
"""ns2:logTransaction"""
@define
class SEnvelope:
_xmlns_S: str
"""@xmlns:S"""
S_Body: SBody
"""S:Body"""
@define
class LogTransactionRequest:
S_Envelope: SEnvelope
"""S:Envelope"""
@classmethod
def from_dict(cls, data: dict[str, Any]):
"""
https://github.com/python-attrs/attrs/issues/417
"""
converter = make_converter()
converter.register_structure_hook(
Ns2LogTransaction,
make_dict_structure_fn(
Ns2LogTransaction, converter, _xmlns_ns2=override(rename="@xmlns:ns2")
),
)
converter.register_structure_hook(
SBody,
make_dict_structure_fn(
SBody,
converter,
ns2_logTransaction=override(rename="ns2:logTransaction"),
),
)
converter.register_structure_hook(
SEnvelope,
make_dict_structure_fn(
SEnvelope,
converter,
_xmlns_S=override(rename="@xmlns:S"),
S_Body=override(rename="S:Body"),
),
)
converter.register_structure_hook(
LogTransactionRequest,
make_dict_structure_fn(
LogTransactionRequest,
converter,
S_Envelope=override(rename="S:Envelope"),
),
)
return converter.structure(data, cls)
if __name__ == "__main__":
d = {
"S:Envelope": {
"@xmlns:S": "http://schemas.xmlsoap.org/soap/envelope/",
"S:Body": {"ns2:logTransaction": {"@xmlns:ns2": "http://random.url/1"}},
}
}
lt = LogTransactionRequest.from_dict(d)
print(lt)
Notable changes:
One other thing: you shouldn't create a converter in the from_dict
function, or if you do it should be cached, otherwise you'll get pretty bad performance.
Cattrs basically generates and compiles functions for un/structuring; this is why the order in which hooks are registered is important and why you want do avoid recreating converters.
Let me know if you have any other questions!
Thank you! this is great! Will heed your advice!
Description
Hi, I have XML files which I want to read and import into structured objects using
attrs
andcattrs
. For xml reading, I'm usingxmltodict
, with the returned dictionary often having keys containing special characters like:
or@
. I've perused this issue https://github.com/python-attrs/attrs/issues/417 and came up with the solution below but I'm getting an error which I don't understand.What I Did
script:
Traceback: