OpenCyphal / pycyphal

Python implementation of the Cyphal protocol stack.
https://pycyphal.readthedocs.io/
MIT License
119 stars 106 forks source link

Improve error messages in pyuavcan.dsdl.update_from_builtin() #116

Closed pavel-kirienko closed 3 years ago

pavel-kirienko commented 4 years ago

An easy mistake:

$ pyuavcan call 42 uavcan.register.Access.1.0 '{name: uavcan.pub.measurement}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 8), 125)'
Error: ValueError: dictionary update sequence element #0 has length 1; 2 is required
2020-06-06 02:38:40 917151 INFO     pyuavcan._cli._main: Unhandled exception: dictionary update sequence element #0 has length 1; 2 is required
Traceback (most recent call last):
  File "/home/pavel/.local/lib/python3.8/site-packages/pyuavcan/_cli/_main.py", line 24, in main
    exit(_main_impl())
  File "/home/pavel/.local/lib/python3.8/site-packages/pyuavcan/_cli/_main.py", line 50, in _main_impl
    result = args.func(args)
  File "/home/pavel/.local/lib/python3.8/site-packages/pyuavcan/_cli/_main.py", line 149, in execute
    return cmd.execute(args, subsystems)
  File "/home/pavel/.local/lib/python3.8/site-packages/pyuavcan/_cli/commands/call.py", line 126, in execute
    request = pyuavcan.dsdl.update_from_builtin(dtype.Request(), args.field_spec)
  File "/home/pavel/.local/lib/python3.8/site-packages/pyuavcan/dsdl/_builtin_form.py", line 149, in update_from_builtin
    update_from_builtin(field_obj, value)
  File "/home/pavel/.local/lib/python3.8/site-packages/pyuavcan/dsdl/_builtin_form.py", line 129, in update_from_builtin
    source = dict(source)   # Create copy to prevent mutation of the original
ValueError: dictionary update sequence element #0 has length 1; 2 is required

The error message is super hard to parse. What it is trying to say is that it found a string 'uavcan.pub.measurement' where it expected a dictionary representing a composite. The correct form would be:

pyuavcan call 42 uavcan.register.Access.1.0 '{name: {name: uavcan.pub.measurement}}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 8), 125)'

I.e.: {name: uavcan.pub.measurement} -> {name: {name: uavcan.pub.measurement}}