-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pyreverse
: add PlantUML output (#4846)
* Extract helper method to get annotated arguments into ``Printer`` base class. * Add ``Printer`` subclass for PlantUML output * Add functional test for ``PlantUmlPrinter`` * Add tests for specific layout for ``PlantUmlPrinter`` * Extract test helper function to remove code duplication * Add new test class to check type annotations * Cleanup generated .puml files after tests finished * Create a factory function to get the correct ``Printer`` class for a given filetype. * Fix unittest after adding a new class to the test data. * Add changelog and whatsnew entry * Add "plantuml" as possible extension for PlantUML output
- Loading branch information
Showing
18 changed files
with
310 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Copyright (c) 2021 Andreas Finkler <andi.finkler@gmail.com> | ||
|
||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html | ||
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE | ||
|
||
""" | ||
Class to generate files in dot format and image formats supported by Graphviz. | ||
""" | ||
from typing import Dict, Optional | ||
|
||
from pylint.pyreverse.printer import EdgeType, Layout, NodeProperties, NodeType, Printer | ||
from pylint.pyreverse.utils import get_annotation_label | ||
|
||
|
||
class PlantUmlPrinter(Printer): | ||
"""Printer for PlantUML diagrams""" | ||
|
||
DEFAULT_COLOR = "black" | ||
|
||
NODES: Dict[NodeType, str] = { | ||
NodeType.CLASS: "class", | ||
NodeType.INTERFACE: "class", | ||
NodeType.PACKAGE: "package", | ||
} | ||
ARROWS: Dict[EdgeType, str] = { | ||
EdgeType.INHERITS: "--|>", | ||
EdgeType.IMPLEMENTS: "..|>", | ||
EdgeType.ASSOCIATION: "--*", | ||
EdgeType.USES: "-->", | ||
} | ||
|
||
def _open_graph(self) -> None: | ||
"""Emit the header lines""" | ||
self.emit("@startuml " + self.title) | ||
if not self.use_automatic_namespace: | ||
self.emit("set namespaceSeparator none") | ||
if self.layout: | ||
if self.layout is Layout.LEFT_TO_RIGHT: | ||
self.emit("left to right direction") | ||
elif self.layout is Layout.TOP_TO_BOTTOM: | ||
self.emit("top to bottom direction") | ||
else: | ||
raise ValueError( | ||
f"Unsupported layout {self.layout}. PlantUmlPrinter only supports left to right and top to bottom layout." | ||
) | ||
|
||
def emit_node( | ||
self, | ||
name: str, | ||
type_: NodeType, | ||
properties: Optional[NodeProperties] = None, | ||
) -> None: | ||
"""Create a new node. Nodes can be classes, packages, participants etc.""" | ||
if properties is None: | ||
properties = NodeProperties(label=name) | ||
stereotype = " << interface >>" if type_ is NodeType.INTERFACE else "" | ||
nodetype = self.NODES[type_] | ||
if properties.color and properties.color != self.DEFAULT_COLOR: | ||
color = f" #{properties.color}" | ||
else: | ||
color = "" | ||
body = "" | ||
if properties.attrs: | ||
body += "\n".join(properties.attrs) | ||
if properties.methods: | ||
body += "\n" | ||
for func in properties.methods: | ||
args = self._get_method_arguments(func) | ||
body += f"\n{func.name}({', '.join(args)})" | ||
if func.returns: | ||
body += " -> " + get_annotation_label(func.returns) | ||
label = properties.label if properties.label is not None else name | ||
if properties.fontcolor and properties.fontcolor != self.DEFAULT_COLOR: | ||
label = f"<color:{properties.fontcolor}>{label}</color>" | ||
self.emit(f'{nodetype} "{label}" as {name}{stereotype}{color} {{\n{body}\n}}') | ||
|
||
def emit_edge( | ||
self, | ||
from_node: str, | ||
to_node: str, | ||
type_: EdgeType, | ||
label: Optional[str] = None, | ||
) -> None: | ||
"""Create an edge from one node to another to display relationships.""" | ||
edge = f"{from_node} {self.ARROWS[type_]} {to_node}" | ||
if label: | ||
edge += f" : {label}" | ||
self.emit(edge) | ||
|
||
def _close_graph(self) -> None: | ||
"""Emit the lines needed to properly close the graph.""" | ||
self.emit("@enduml") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright (c) 2021 Andreas Finkler <andi.finkler@gmail.com> | ||
|
||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html | ||
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE | ||
|
||
from typing import Type | ||
|
||
from pylint.pyreverse.dot_printer import DotPrinter | ||
from pylint.pyreverse.plantuml_printer import PlantUmlPrinter | ||
from pylint.pyreverse.printer import Printer | ||
from pylint.pyreverse.vcg_printer import VCGPrinter | ||
|
||
filetype_to_printer = { | ||
"vcg": VCGPrinter, | ||
"plantuml": PlantUmlPrinter, | ||
"puml": PlantUmlPrinter, | ||
"dot": DotPrinter, | ||
} | ||
|
||
|
||
def get_printer_for_filetype(filetype: str) -> Type[Printer]: | ||
return filetype_to_printer.get(filetype, DotPrinter) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
@startuml classes_No_Name | ||
set namespaceSeparator none | ||
class "Ancestor" as data.clientmodule_test.Ancestor { | ||
attr : str | ||
cls_member | ||
|
||
get_value() | ||
set_value(value) | ||
} | ||
class "<color:red>CustomException</color>" as data.suppliermodule_test.CustomException { | ||
|
||
} | ||
class "DoNothing" as data.suppliermodule_test.DoNothing { | ||
|
||
} | ||
class "DoNothing2" as data.suppliermodule_test.DoNothing2 { | ||
|
||
} | ||
class "DoSomething" as data.suppliermodule_test.DoSomething { | ||
my_int : Optional[int] | ||
my_string : str | ||
|
||
do_it(new_int: int) -> int | ||
} | ||
class "Interface" as data.suppliermodule_test.Interface { | ||
|
||
|
||
get_value() | ||
set_value(value) | ||
} | ||
class "Specialization" as data.clientmodule_test.Specialization { | ||
TYPE : str | ||
relation | ||
relation2 | ||
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 | ||
data.suppliermodule_test.DoNothing2 --* data.clientmodule_test.Specialization : relation2 | ||
@enduml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@startuml packages_No_Name | ||
set namespaceSeparator none | ||
package "data" as data { | ||
|
||
} | ||
package "data.clientmodule_test" as data.clientmodule_test { | ||
|
||
} | ||
package "data.suppliermodule_test" as data.suppliermodule_test { | ||
|
||
} | ||
data.clientmodule_test --> data.suppliermodule_test | ||
@enduml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.