robshakir / pyangbind

A plugin for pyang that creates Python bindings for a YANG model.
Other
204 stars 121 forks source link

pyangbind fails processing typedef union with default value #317

Closed gunhanoral closed 1 year ago

gunhanoral commented 1 year ago

When trying to process Cisco-NX-OS-device.yang I encountered this error:

❯ docker run --rm -it --name pyangbind -v "$PWD/$YANGFILE:/$YANGFILE" pyangbind:v0.8.3p1 -V -o cisco_nxos.py $YANGFILE
# module search path: .:/usr/local/share/yang/modules
# read Cisco-NX-OS-device.yang (CL)
# READ Cisco-NX-OS-device.yang
Traceback (most recent call last):
  File "/usr/local/bin/pyang", line 580, in <module>
    run()
  File "/usr/local/bin/pyang", line 549, in run
    emit_obj.emit(ctx, modules, fd)
  File "/usr/local/lib/python3.9/site-packages/pyangbind/plugin/pybind.py", line 201, in emit
    build_pybind(ctx, modules, fd)
  File "/usr/local/lib/python3.9/site-packages/pyangbind/plugin/pybind.py", line 404, in build_pybind
    build_typedefs(ctx, defn["typedef"])
  File "/usr/local/lib/python3.9/site-packages/pyangbind/plugin/pybind.py", line 642, in build_typedefs
    class_map[type_name]["quote_default"] = default[1]
IndexError: string index out of range

Below is the problematic section in the yang file:

typedef mo_TStamp {
    type union {
        type string;
        type uint64;
    }
    default "0";
}

I'm not familiar with yang that much so I don't know if the section above is valid or not. I checked RFC 7950, didn't understand much :) and assumed it is valid.

I found out on this section of pybind.py expects the variable "default" as a tuple. But if the type is union (after line 612), variable "default" is set as either boolean False or the default value declared on typedef ("0" in this case)(L618). And if there are no default values in the elements, the variable "default" is still a boolean False or a string (or whatever). Not a tuple. So L641 or L642 fails depending on the length of the default value. In my case L642 failed because string "0" didn't have index 1.

To fix this issue I made the changes below. It helped with my case and I was able to generate pyangbind classes for Nexus.

if default:  # L640
    if not isinstance(default, tuple):
        q = True if "quote_arg" in i[1] else False
        default = (default, q)
    class_map[type_name]["default"] = default[0]
    class_map[type_name]["quote_default"] = default[1]

I'm not confident it is a correct fix. So I wanted to open an issue and discuss it.