mbj4668 / pyang

An extensible YANG validator and converter in python
ISC License
528 stars 342 forks source link

UML Plugin: Fix issues with the rendering of identities, identityrefs, typedefs, leafrefs #876

Closed nkhancock closed 8 months ago

nkhancock commented 11 months ago

This pull request fixes issues with the rendering of identities, identities, typedefs and leafrefs and relations associated with them:

  1. Fix missing stereotype \<\<enumeration>> on the enumeration class.
  2. Fix the false identification of the source of an identityref when the source is a typedef.
  3. Fix multiple identical base ids in self.baseid which result in duplicate definitions in the PlantUML code (note this has no effect on the diagram as such).
  4. Fix multiple identical identities in self.identities which result in duplicate definitions in the PlantUML code (note this has no effect on the diagram as such).
  5. Fix base identities from being rendered in modules in which they are not used.
    • This was caused by a typo in attribute name in the function post_process_module(), so that the list of base identities in the module being processed is not emptied before the next module is processed (self.based to self.baseid).
  6. Fix an issue where bases for identityrefs are not added to self.baseid and therefore not rendered as a placeholder class, if the base is not defined within the set of input modules.
  7. Fix an issue to add relations defined for identityrefs that cross between 2 input modules outside the scope of the packages representing the input modules.
    • This required adding a new attribute self.end_strings to collect such relation strings during processing of the modules and appending to the file in the function post_process_diagram().
  8. Fix keyword scoping issues and clashing keywords
    • In YANG it is permitted to give the same name to a feature, identity, typedef and top-level data nodes within a single module. In addition, the same name can be used in different modules to define different features, identities, typedefs and top-level data nodes. However, the current UML plugin does not take this into account resulting in name clashes.
    • PlantUML keywords are now generated for classes representing identities and typedefs to include either an ‘_identity’ or ‘_typedef’ suffix to ensure uniqueness of keywords across typedef and identity definitions
    • The module prefix is always included when referencing identities and baseids within the UML plugin code and PlantUML keywords are always generated from prefix + name to ensure uniqueness across modules.
  9. Fix name clashes with placeholder classes representing leafref targets not within the input modules
    • The suffix ‘-leafref’ is added to leafref placeholder classes to avoid the name clashes with existing class definitions.
  10. Fixes an issue with identifying in which module the target node is located by augmented schemas
    • The module in which a target node is located is now identified by the prefix associated with the last node in the XPath expression.

Note that other issues need addressing in a future pull requests such as the issue where individual node prefixes within XPath expressions are not taken into account when defining keywords for data nodes which leads to issues when handling XPaths for augmentations, e.g., when 2 augmentations augment the same named node but under different module prefixes, e.g., the nodes ‘line’ in the modules bbf-fast and bbf-vdsl. Due to its impact on the existing code, this issue was not addressed with this pull request.

nkhancock commented 11 months ago

The following examples illustrate what has been fixed.

The following YANG data models were used to test these fixes:

test-module-common ``` module test-module-common { namespace "http://www.example.com/ns/yang/test-module-common"; prefix tst-mod-c; revision 2023-07-17 { description "Initial revision."; reference "None."; } identity base-identity { description "..."; } } ```
test-module-1 ``` module test-module-1 { namespace "http://www.example.com/ns/yang/test-module-1"; prefix tst-mod-1; import test-module-common { prefix tst-mod-c; } revision 2023-07-17 { description "Initial revision."; reference "None."; } identity base-id { description "Base identity for my identities."; } identity id-1 { base base-id; description "..."; } identity id-2 { base base-id; description "..."; } identity id-3 { base id-2; description "..."; } identity module-1-identity { base tst-mod-c:base-identity; description "..."; } typedef direction { type enumeration { enum up { description "..."; } enum down { description "..."; } } } typedef base-id-ref { type identityref { base base-id; } description "..."; } container refs { description "..."; list list { key name; description "..."; leaf name { type string; description "..."; } leaf id { type identityref { base base-id; } description "..."; } } } } ```
test-module-2 ``` module test-module-2 { namespace "http://www.example.com/ns/yang/test-module-2"; prefix tst-mod-2; import test-module-1 { prefix tst-mod-1; } revision 2023-07-17 { description "Initial revision."; reference "None."; } identity another-id { base tst-mod-1:base-id; description "..."; } typedef list-ref { type leafref { path "/tst-mod-1:refs" + "/tst-mod-1:list" + "/tst-mod-1:name"; } description "---."; } typedef selection-ref { type leafref { path "/tst-mod-1:refs" + "/tst-mod-1:list" + "/tst-mod-2:select" + "/tst-mod-2:name"; } description "---."; } typedef id-2-ref { type identityref { base tst-mod-1:id-2; } description "..."; } augment "/tst-mod-1:refs/tst-mod-1:list" { description "..."; list select { key name; description "..."; leaf name { type string; description "..."; } leaf thing-1 { type list-ref; description "..."; } leaf thing-2 { type leafref { path "/tst-mod-1:refs" + "/tst-mod-1:list" + "/tst-mod-1:name"; } description "..."; } leaf remote-identity { type identityref { base tst-mod-1:id-3; } description ".."; } } } } ```
test-identifier-clash ``` module test-identifier-clash { yang-version 1.1; namespace "http://www.example.com/ns/yang/test-identifier-clash"; prefix tst-id-clsh; revision 2023-07-17 { description "Initial revision."; reference "None."; } feature direction { description "Indicates that directions as typedef are supported."; } identity direction { if-feature direction; description "Base identity for my identities."; } identity up { base direction; description "..."; } identity down { base direction; description "..."; } typedef direction { type enumeration { enum up { description "..."; } enum down { description "..."; } } } container direction { description ""; leaf direction { type direction; description "..."; } leaf another-direction { type identityref { base direction; } description "..."; } } } ```

Example 1

Before the fixes:

image

After the fixes:

image

Example 2

Before the fixes:

image

After the fixes:

image

Example 3

Before the fixes:

image

After the fixes:

image

Example 4

Before the fixes:

image

Blue: The keywords generated for the enumeration class direction and the \<\<container>> class direction are identical, i.e., _test_identifier_clash_Idirection and thus clash (addressed by fix 8).

After the fixes:

image