I have some nested python OrderedDicts, e.g
# The Object we need to convert
od = OrderedDict(
[
('header', OrderedDict(
[
('stamp', OrderedDict(
[
('sec', 42),
('nanosec', 99)
]
)
),
('frame_id', 'world')
]
)
),
('name', ['x', 'y', 'z']),
('position', [1.0, 2.0, 3.0]),
('velocity', [0.0, 0.0, 0.0]),
('effort', [0.0, 0.0, 0.0])
]
)
And I need to convert this into a QJSValue.
The function that does this can be given a QJSValue prototype if needed. Here is a prototype for the above value. This might makes things easier, especially when it comes to converting the list parts.
# A JS Prototype that has the feilds and types, and just needs its values populating
app = QCoreApplication()
engine = QJSEngine()
joint_state_msg_js = engine.newObject()
header_msg_js = engine.newObject()
stamp_msg_js = engine.newObject()
stamp_msg_js.setProperty('sec',0)
stamp_msg_js.setProperty('nanosec',0)
header_msg_js.setProperty('stamp', stamp_msg_js)
header_msg_js.setProperty('frame_id', '')
joint_state_msg_js.setProperty('header', header_msg_js)
joint_state_msg_js.setProperty('name', engine.newArray(3))
joint_state_msg_js.setProperty('position', engine.newArray(3))
joint_state_msg_js.setProperty('velocity', engine.newArray(3))
joint_state_msg_js.setProperty('effort', engine.newArray(3))
prototype = joint_state_msg_js
print(prototype.toVariant())
The OrderedDict could have any depth.
I keep trying to write a function that creates a QJSValue from the OrderedDict, or populates the prototype values, but I cannot figure out how to do either. It needs to work with any OrderedDict (any OrderedDict of primatives or other OrderedDicts).
How could I write this function?
Here is one of my attempts:
def to_qjs_value(od: OrderedDict, prototype: QJSValue) -> QJSValue:
for field_name in od:
inner_dict_or_value = od[field_name]
if isinstance(inner_dict_or_value, OrderedDict):
inner_dict = inner_dict_or_value
inner_dict_js = to_qjs_value(inner_dict, prototype) # recursion
prototype.setProperty(field_name, inner_dict_js)
else:
inner_value = inner_dict_or_value
if isinstance(inner_value, list):
jslist = QJSValue()
i=0
for inner_list_value in inner_value:
jslist.setProperty(i, inner_list_value)
i=i+1
prototype.setProperty(field_name, jslist)
else:
prototype.setProperty(field_name, inner_value)
return prototype
but this makes the result flat, and doesn't populate the lists.
{
'effort': None,
'frame_id': 'world',
'header': {},
'name': None,
'nanosec': 99,
'position': None,
'sec': 42,
'stamp': {},
'velocity': None
}
Either a solution with or without using the prototype will be fine.
One possible solution is to convert the dictionary to string json using json.dumps()
, and then the string to objects using JSON.Parse
:
app = QCoreApplication()
engine = QJSEngine()
od_json = json.dumps(od)
converter = engine.evaluate("JSON.parse")
qjsvalue = converter.call([QJSValue(od_json)])
assert (
qjsvalue.property("header").property("stamp").property("sec").equals(QJSValue(42.0))
)