Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permit to generate plantuml diagram with pyreverse #4498

Closed
Pierre-Sassoulas opened this issue May 24, 2021 · 5 comments · Fixed by #4846
Closed

Permit to generate plantuml diagram with pyreverse #4498

Pierre-Sassoulas opened this issue May 24, 2021 · 5 comments · Fixed by #4846
Assignees
Labels
Enhancement ✨ Improvement to a component pyreverse Related to pyreverse component

Comments

@Pierre-Sassoulas
Copy link
Member

Describe the solution you'd like

Permit to generate plantuml code in output of pyreverse

Additional context

#4488

@Pierre-Sassoulas Pierre-Sassoulas added Enhancement ✨ Improvement to a component pyreverse Related to pyreverse component labels May 24, 2021
@DudeNr33
Copy link
Collaborator

You can assign this issue to me - I have implemented a first basic draft. Implementing a PlantUml Writer and Printer class analogous to the DOT variants is straightforward.

However, there is one thing that I want to look into a bit further.
One big advantage of PlantUML is that even the text output is human readable.
IMO an important use case for the PlantUML backend would be to generate a diagram from the existing code, and then use that to reason about changes to the software design, by modifying the diagrams and thus illustrating the proposed changes.

Currently however the diagram generation relies on IDs to identify elements.
The test data for pyreverse would look like this in PlantUML:

@startuml plantuml
class "Ancestor" as 0 {
    attr : str
    cls_member
    get_value()
    set_value(value)
}
class "DoNothing" as 1 {
}
class "Interface" as 2 {
    get_value()
    set_value(value)
}
class "Specialization" as 3 {
    TYPE : str
    relation
    top : str
}
3 --|> 0
0 ..|> 2
1 --* 0 : cls_member
1 --* 3 : relation
@enduml

While four classes are somewhat OK to remember by ID, this becomes unwieldy if the number of classes grows.

If someone wants to work with the file and modify it, it would be much more convenient if it could look like this:

@startuml plantuml
class Ancestor {
    attr : str
    cls_member
    get_value()
    set_value(value)
}
class DoNothing {
}
class Interface {
    get_value()
    set_value(value)
}
class Specialization {
    TYPE : str
    relation
    top : str
}
Specialization --|> Ancestor
Ancestor ..|> Interface
DoNothing --* Ancestor : cls_member
DoNothing --* Specialization : relation
@enduml

The need for IDs is of course due to the possibility that two classes in different modules can have the same name, which is not necessarily included in the diagram.
I have to dig a bit deeper into the code to see if there is a viable solution to solve this. Maybe only use the IDs if multiple classes (or modules, for package diagrams) with the same name exist.

@Pierre-Sassoulas
Copy link
Member Author

Hey, thank you for tackling this, much appreciated ! The way I solved this issue when I was doing plantuml diagram was to use package. Would that be possible here ?

@startuml

package foo1 <<Node>> {
    class Ancestor {
        attr : str
        cls_member
        get_value()
        set_value(value)
    }
}

package foo2 <<Rectangle>> {
    class Ancestor {
        attr : str
        cls_member
        get_value()
        set_value(value)
    }
}

package foo3 <<Frame>> {
    class DoNothing {
    }
    class Interface {
        get_value()
        set_value(value)
    }
    class Specialization {
        TYPE : str
        relation
        top : str
    }
    DoNothing --* Specialization : relation
}

foo3.Specialization --|> foo1.Ancestor
foo1.Ancestor ..|> foo3.Interface
foo3.DoNothing --* foo1.Ancestor : cls_member

@enduml

@DudeNr33
Copy link
Collaborator

The way the DiagramWriter and DiadefsHandler classes are currently implemented not directly - they clearly distinguish between class objects and packages, as package and class diagrams are generated independently.
Thus, including a hierarchy of package->subpackage->class like in your example is not really possible.

Packages however can be automatically generated by using set namespaceSeparator ..
This however mandates the use of the option --module_names, which is False by default.
(When setting it to True, the problem with name conflicts would be gone anyway, even without using packages).

One could use IDs if --module_names is set to False and proper names if it is True.
Or try to use proper names always and only fall back to IDs if multiple classes with the same name exist.
Or generate unique names by prepending module and optionally package name for conflicting classes, so the name is always as short as possible while still remaining unique (this would be pretty much like PyCharm does it in the files tab).

@DudeNr33
Copy link
Collaborator

Sometimes the solution can be so simple - just use the full qualified name instead of the ID.

@startuml classes
set namespaceSeparator none
class "Ancestor" as data.clientmodule_test.Ancestor #aliceblue {
attr : str
cls_member
get_value()
set_value(value)
}
class "DoNothing" as data.suppliermodule_test.DoNothing #aliceblue {

}
class "Interface" as data.suppliermodule_test.Interface #aliceblue {
get_value()
set_value(value)
}
class "Specialization" as data.clientmodule_test.Specialization #aliceblue {
TYPE : str
relation
top : str
}
data.clientmodule_test.Specialization --|> data.clientmodule_test.Ancestor
data.clientmodule_test.Ancestor ..|> data.suppliermodule_test.Interface
data.suppliermodule_test.DoNothing --* data.clientmodule_test.Ancestor : cls_member
data.suppliermodule_test.DoNothing --* data.clientmodule_test.Specialization : relation
@enduml

The classes appear with just their class name in the diagram, and the aliases are unique.

@Pierre-Sassoulas
Copy link
Member Author

Wow, this is neat, I'm pretty sure if plantuml is going to be used a lot !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement ✨ Improvement to a component pyreverse Related to pyreverse component
Projects
None yet
2 participants