CZ-NIC / yangson

GNU Lesser General Public License v3.0
53 stars 20 forks source link

yangson.exceptions.DefinitionNotFound: grouping grouping1 #98

Closed JHolcman-T closed 3 years ago

JHolcman-T commented 3 years ago

There is an issue when grouping from Submodule is not defined on the first layer (first layer after submodule statement). However when Groping statement is defined on first layer there is no Issue.

Exception message

Traceback (most recent call last):
  File "/snap/pycharm-community/226/plugins/python-ce/helpers/pydev/pydevd.py", line 1477, in _exec
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/snap/pycharm-community/226/plugins/python-ce/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/json_builder/__main__.py", line 54, in <module>
    dm = DataModel.from_file(b.json_file.name, tuple(paths))
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/datamodel.py", line 60, in from_file
    return cls(yltxt, mod_path, description)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/datamodel.py", line 87, in __init__
    self._build_schema()
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/datamodel.py", line 197, in _build_schema
    self.schema._handle_substatements(
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 248, in _handle_substatements
    method(s, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 696, in _container_stmt
    self._handle_child(ContainerNode(), stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 781, in _handle_child
    super()._handle_child(node, stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 645, in _handle_child
    node._handle_substatements(stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 248, in _handle_substatements
    method(s, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 696, in _container_stmt
    self._handle_child(ContainerNode(), stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 645, in _handle_child
    node._handle_substatements(stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 248, in _handle_substatements
    method(s, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 696, in _container_stmt
    self._handle_child(ContainerNode(), stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 645, in _handle_child
    node._handle_substatements(stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 248, in _handle_substatements
    method(s, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemanode.py", line 676, in _uses_stmt
    grp, gid = sctx.schema_data.get_definition(stmt, sctx)
  File "/home/hjm02/PycharmProjects/yang_diff_wab/virtual_environment_p_3.9.0/lib/python3.9/site-packages/yangson/schemadata.py", line 453, in get_definition
    raise DefinitionNotFound(kw, stmt.argument)
yangson.exceptions.DefinitionNotFound: grouping grouping1

Json Modules-State

{
  "ietf-yang-library:modules-state": {
    "module-set-id": "0",
    "module": [
      {
        "name": "test",
        "namespace": "test.com",
        "revision": "",
        "conformance-type": "implement"
      },
      {
        "name": "test2",
        "namespace": "test2.com",
        "revision": "",
        "conformance-type": "implement",
        "submodule": [
          {
            "name": "testsubmodule",
            "revision": ""
          }
        ]
      }
    ]
  }
}

Main Module

module test2 {

  yang-version "1.1";
  namespace "test2.com";
  prefix test2;

  include testsubmodule;

  container main2 {
    leaf leaf2 {
        type string;
    }
  }
}

Submodule

submodule testsubmodule {

    yang-version 1.1;

    belongs-to test2 {
        prefix test2;
    }

    container container1 {
        container container2 {
           grouping grouping1 {
                leaf grouping-leaf {
                    type string;
                }
            }
            container container3 {
                uses grouping1;
                leaf test-leaf {
                    type uint8;
                }
            }
        }
    }
}

So I changed "get_definition()" function to recursive one in schemadata.py at line 414

Original one:

    def get_definition(self: "SchemaData", stmt: Statement,
                       sctx: SchemaContext) -> Tuple[Statement, SchemaContext]:
        """Find the statement defining a grouping or derived type.

        Args:
            stmt: YANG "uses" or "type" statement.
            sctx: Schema context where the definition is used.

        Returns:
            A tuple consisting of the definition statement ('grouping' or
            'typedef') and schema context of the definition.

        Raises:
            ValueError: If `stmt` is neither "uses" nor "type" statement.
            ModuleNotRegistered: If `mid` is not registered in the data model.
            UnknownPrefix: If the prefix specified in the argument of `stmt`
                is not declared.
            DefinitionNotFound: If the corresponding definition is not found.
        """
        if stmt.keyword == "uses":
            kw = "grouping"
        elif stmt.keyword == "type":
            kw = "typedef"
        else:
            raise ValueError("not a 'uses' or 'type' statement")
        loc, did = self.resolve_pname(stmt.argument, sctx.text_mid)
        if did == sctx.text_mid:
            dstmt = stmt.get_definition(loc, kw)
            if dstmt:
                return (dstmt, sctx)
        else:
            dstmt = self.modules[did].statement.find1(kw, loc)
            if dstmt:
                return (dstmt, SchemaContext(sctx.schema_data, sctx.default_ns, did))
        for sid in self.modules[did].submodules:
            dstmt = self.modules[sid].statement.find1(kw, loc)
            if dstmt:
                return (
                    dstmt, SchemaContext(sctx.schema_data, sctx.default_ns, sid))
        raise DefinitionNotFound(kw, stmt.argument)

Changed one:

    def get_definition(self: "SchemaData", stmt: Statement,
                       sctx: SchemaContext) -> Tuple[Statement, SchemaContext]:
        """Find the statement defining a grouping or derived type.

        Args:
            stmt: YANG "uses" or "type" statement.
            sctx: Schema context where the definition is used.

        Returns:
            A tuple consisting of the definition statement ('grouping' or
            'typedef') and schema context of the definition.

        Raises:
            ValueError: If `stmt` is neither "uses" nor "type" statement.
            ModuleNotRegistered: If `mid` is not registered in the data model.
            UnknownPrefix: If the prefix specified in the argument of `stmt`
                is not declared.
            DefinitionNotFound: If the corresponding definition is not found.
        """
        if stmt.keyword == "uses":
            kw = "grouping"
        elif stmt.keyword == "type":
            kw = "typedef"
        else:
            raise ValueError("not a 'uses' or 'type' statement")
        loc, did = self.resolve_pname(stmt.argument, sctx.text_mid)
        if did == sctx.text_mid:
            dstmt = stmt.get_definition(loc, kw)
            if dstmt:
                return (dstmt, sctx)
        else:
            dstmt = self.modules[did].statement.find1(kw, loc)
            if dstmt:
                return (dstmt, SchemaContext(sctx.schema_data, sctx.default_ns, did))

        global value
        value = None

        for sid in self.modules[did].submodules:
            def rekk(_statement):
                global value
                if isinstance(_statement, list):
                    if _statement:
                        for statement in _statement:
                            dstmt = statement.find1(kw, loc)
                            if dstmt and value is None:
                                value = dstmt, SchemaContext(sctx.schema_data, sctx.default_ns, sid)
                            if value is not None:
                                break
                            if statement == _statement[-1]:
                                for statement in _statement:
                                    rekk(statement.substatements)
                elif _statement is not None:
                    dstmt = _statement.find1(kw, loc)
                    if dstmt and value is None:
                        value = dstmt, SchemaContext(sctx.schema_data, sctx.default_ns, sid)
                    if value is not None:
                        return value
                    rekk(_statement.substatements)
            rekk(self.modules[sid].statement)
        return value

        raise DefinitionNotFound(kw, stmt.argument)

I know it is not beautiful but hey it works!

llhotka commented 3 years ago

Fixed in f55460255ee2e712cf900f3de787f4e1420d836c, thanks.