Skip to content

Commit 0d26e3c

Browse files
DudeNr33Pierre-SassoulasDanielNoord
authored
pyreverse: use colorblind friendly default colors (#8415)
Using Paul Tol's colorblind palette. Also enable both hex codes and css/html color names Co-authored-by: Pierre Sassoulas <[email protected]> Co-authored-by: Daniël van Noord <[email protected]>
1 parent ceb2410 commit 0d26e3c

File tree

12 files changed

+59
-49
lines changed

12 files changed

+59
-49
lines changed

.pyenchant_pylint_custom_dict.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ globbing
132132
GPL
133133
graphname
134134
graphviz
135+
grey
135136
guido's
136137
gv
137138
hashable

doc/whatsnew/fragments/8251.breaking

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
`pyreverse` now uses a new default color palette that is more colorblind friendly.
2+
The color scheme is taken from `Paul Tol's Notes <https://personal.sron.nl/~pault/>`_.
3+
If you prefer other colors, you can use the `--color-palette` option to specify custom colors.
4+
5+
Closes #8251

pylint/pyreverse/main.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,16 @@
3434
)
3535

3636
DEFAULT_COLOR_PALETTE = (
37-
"aliceblue",
38-
"antiquewhite",
39-
"aquamarine",
40-
"burlywood",
41-
"cadetblue",
42-
"chartreuse",
43-
"chocolate",
44-
"coral",
45-
"cornflowerblue",
46-
"cyan",
47-
"darkgoldenrod",
48-
"darkseagreen",
49-
"dodgerblue",
50-
"forestgreen",
51-
"gold",
52-
"hotpink",
53-
"mediumspringgreen",
37+
# colorblind scheme taken from https://personal.sron.nl/~pault/
38+
"#77AADD", # light blue
39+
"#99DDFF", # light cyan
40+
"#44BB99", # mint
41+
"#BBCC33", # pear
42+
"#AAAA00", # olive
43+
"#EEDD88", # light yellow
44+
"#EE8866", # orange
45+
"#FFAABB", # pink
46+
"#DDDDDD", # pale grey
5447
)
5548

5649
OPTIONS: Options = (

pylint/pyreverse/plantuml_printer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def emit_node(
5656
properties = NodeProperties(label=name)
5757
nodetype = self.NODES[type_]
5858
if properties.color and properties.color != self.DEFAULT_COLOR:
59-
color = f" #{properties.color}"
59+
color = f" #{properties.color.lstrip('#')}"
6060
else:
6161
color = ""
6262
body = []

tests/pyreverse/data/classes_colorized.dot

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
digraph "classes_colorized" {
22
rankdir=BT
33
charset="utf-8"
4-
"data.clientmodule_test.Ancestor" [color="aliceblue", fontcolor="black", label=<{Ancestor|attr : str<br ALIGN="LEFT"/>cls_member<br ALIGN="LEFT"/>|get_value()<br ALIGN="LEFT"/>set_value(value)<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
5-
"data.suppliermodule_test.CustomException" [color="aliceblue", fontcolor="red", label=<{CustomException|<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
6-
"data.suppliermodule_test.DoNothing" [color="aliceblue", fontcolor="black", label=<{DoNothing|<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
7-
"data.suppliermodule_test.DoNothing2" [color="aliceblue", fontcolor="black", label=<{DoNothing2|<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
8-
"data.suppliermodule_test.DoSomething" [color="aliceblue", fontcolor="black", label=<{DoSomething|my_int : Optional[int]<br ALIGN="LEFT"/>my_int_2 : Optional[int]<br ALIGN="LEFT"/>my_string : str<br ALIGN="LEFT"/>|do_it(new_int: int): int<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
9-
"data.suppliermodule_test.Interface" [color="aliceblue", fontcolor="black", label=<{Interface|<br ALIGN="LEFT"/>|<I>get_value</I>()<br ALIGN="LEFT"/><I>set_value</I>(value)<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
10-
"data.property_pattern.PropertyPatterns" [color="aliceblue", fontcolor="black", label=<{PropertyPatterns|prop1<br ALIGN="LEFT"/>prop2<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
11-
"data.clientmodule_test.Specialization" [color="aliceblue", fontcolor="black", label=<{Specialization|TYPE : str<br ALIGN="LEFT"/>relation<br ALIGN="LEFT"/>relation2<br ALIGN="LEFT"/>top : str<br ALIGN="LEFT"/>|from_value(value: int)<br ALIGN="LEFT"/>increment_value(): None<br ALIGN="LEFT"/>transform_value(value: int): int<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
4+
"data.clientmodule_test.Ancestor" [color="#77AADD", fontcolor="black", label=<{Ancestor|attr : str<br ALIGN="LEFT"/>cls_member<br ALIGN="LEFT"/>|get_value()<br ALIGN="LEFT"/>set_value(value)<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
5+
"data.suppliermodule_test.CustomException" [color="#77AADD", fontcolor="red", label=<{CustomException|<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
6+
"data.suppliermodule_test.DoNothing" [color="#77AADD", fontcolor="black", label=<{DoNothing|<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
7+
"data.suppliermodule_test.DoNothing2" [color="#77AADD", fontcolor="black", label=<{DoNothing2|<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
8+
"data.suppliermodule_test.DoSomething" [color="#77AADD", fontcolor="black", label=<{DoSomething|my_int : Optional[int]<br ALIGN="LEFT"/>my_int_2 : Optional[int]<br ALIGN="LEFT"/>my_string : str<br ALIGN="LEFT"/>|do_it(new_int: int): int<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
9+
"data.suppliermodule_test.Interface" [color="#77AADD", fontcolor="black", label=<{Interface|<br ALIGN="LEFT"/>|<I>get_value</I>()<br ALIGN="LEFT"/><I>set_value</I>(value)<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
10+
"data.property_pattern.PropertyPatterns" [color="#77AADD", fontcolor="black", label=<{PropertyPatterns|prop1<br ALIGN="LEFT"/>prop2<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
11+
"data.clientmodule_test.Specialization" [color="#77AADD", fontcolor="black", label=<{Specialization|TYPE : str<br ALIGN="LEFT"/>relation<br ALIGN="LEFT"/>relation2<br ALIGN="LEFT"/>top : str<br ALIGN="LEFT"/>|from_value(value: int)<br ALIGN="LEFT"/>increment_value(): None<br ALIGN="LEFT"/>transform_value(value: int): int<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
1212
"data.clientmodule_test.Specialization" -> "data.clientmodule_test.Ancestor" [arrowhead="empty", arrowtail="none"];
1313
"data.suppliermodule_test.DoNothing" -> "data.clientmodule_test.Ancestor" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="cls_member", style="solid"];
1414
"data.suppliermodule_test.DoNothing" -> "data.clientmodule_test.Specialization" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="relation", style="solid"];

tests/pyreverse/data/classes_colorized.puml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
@startuml classes_colorized
22
set namespaceSeparator none
3-
class "Ancestor" as data.clientmodule_test.Ancestor #aliceblue {
3+
class "Ancestor" as data.clientmodule_test.Ancestor #77AADD {
44
attr : str
55
cls_member
66
get_value()
77
set_value(value)
88
}
9-
class "<color:red>CustomException</color>" as data.suppliermodule_test.CustomException #aliceblue {
9+
class "<color:red>CustomException</color>" as data.suppliermodule_test.CustomException #77AADD {
1010
}
11-
class "DoNothing" as data.suppliermodule_test.DoNothing #aliceblue {
11+
class "DoNothing" as data.suppliermodule_test.DoNothing #77AADD {
1212
}
13-
class "DoNothing2" as data.suppliermodule_test.DoNothing2 #aliceblue {
13+
class "DoNothing2" as data.suppliermodule_test.DoNothing2 #77AADD {
1414
}
15-
class "DoSomething" as data.suppliermodule_test.DoSomething #aliceblue {
15+
class "DoSomething" as data.suppliermodule_test.DoSomething #77AADD {
1616
my_int : Optional[int]
1717
my_int_2 : Optional[int]
1818
my_string : str
1919
do_it(new_int: int) -> int
2020
}
21-
class "Interface" as data.suppliermodule_test.Interface #aliceblue {
21+
class "Interface" as data.suppliermodule_test.Interface #77AADD {
2222
{abstract}get_value()
2323
{abstract}set_value(value)
2424
}
25-
class "PropertyPatterns" as data.property_pattern.PropertyPatterns #aliceblue {
25+
class "PropertyPatterns" as data.property_pattern.PropertyPatterns #77AADD {
2626
prop1
2727
prop2
2828
}
29-
class "Specialization" as data.clientmodule_test.Specialization #aliceblue {
29+
class "Specialization" as data.clientmodule_test.Specialization #77AADD {
3030
TYPE : str
3131
relation
3232
relation2
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
digraph "packages_colorized" {
22
rankdir=BT
33
charset="utf-8"
4-
"data" [color="aliceblue", label=<data>, shape="box", style="filled"];
5-
"data.clientmodule_test" [color="aliceblue", label=<data.clientmodule_test>, shape="box", style="filled"];
6-
"data.property_pattern" [color="aliceblue", label=<data.property_pattern>, shape="box", style="filled"];
7-
"data.suppliermodule_test" [color="aliceblue", label=<data.suppliermodule_test>, shape="box", style="filled"];
4+
"data" [color="#77AADD", label=<data>, shape="box", style="filled"];
5+
"data.clientmodule_test" [color="#77AADD", label=<data.clientmodule_test>, shape="box", style="filled"];
6+
"data.property_pattern" [color="#77AADD", label=<data.property_pattern>, shape="box", style="filled"];
7+
"data.suppliermodule_test" [color="#77AADD", label=<data.suppliermodule_test>, shape="box", style="filled"];
88
"data.clientmodule_test" -> "data.suppliermodule_test" [arrowhead="open", arrowtail="none"];
99
}

tests/pyreverse/data/packages_colorized.puml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
@startuml packages_colorized
22
set namespaceSeparator none
3-
package "data" as data #aliceblue {
3+
package "data" as data #77AADD {
44

55
}
6-
package "data.clientmodule_test" as data.clientmodule_test #aliceblue {
6+
package "data.clientmodule_test" as data.clientmodule_test #77AADD {
77

88
}
9-
package "data.property_pattern" as data.property_pattern #aliceblue {
9+
package "data.property_pattern" as data.property_pattern #77AADD {
1010

1111
}
12-
package "data.suppliermodule_test" as data.suppliermodule_test #aliceblue {
12+
package "data.suppliermodule_test" as data.suppliermodule_test #77AADD {
1313

1414
}
1515
data.clientmodule_test --> data.suppliermodule_test

tests/pyreverse/functional/class_diagrams/colorized_output/colorized.puml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
@startuml classes
22
set namespaceSeparator none
3-
class "CheckerCollector" as colorized.CheckerCollector #aliceblue {
3+
class "CheckerCollector" as colorized.CheckerCollector #77AADD {
44
checker1
55
checker2
66
checker3
77
}
8-
class "ElseifUsedChecker" as pylint.extensions.check_elif.ElseifUsedChecker #antiquewhite {
8+
class "ElseifUsedChecker" as pylint.extensions.check_elif.ElseifUsedChecker #99DDFF {
99
msgs : dict
1010
name : str
1111
leave_module(_: nodes.Module) -> None
1212
process_tokens(tokens: list[TokenInfo]) -> None
1313
visit_if(node: nodes.If) -> None
1414
}
15-
class "ExceptionsChecker" as pylint.checkers.exceptions.ExceptionsChecker #aquamarine {
15+
class "ExceptionsChecker" as pylint.checkers.exceptions.ExceptionsChecker #44BB99 {
1616
msgs : dict
1717
name : str
1818
options : tuple
@@ -22,7 +22,7 @@ class "ExceptionsChecker" as pylint.checkers.exceptions.ExceptionsChecker #aquam
2222
visit_raise(node: nodes.Raise) -> None
2323
visit_tryexcept(node: nodes.TryExcept) -> None
2424
}
25-
class "StdlibChecker" as pylint.checkers.stdlib.StdlibChecker #aquamarine {
25+
class "StdlibChecker" as pylint.checkers.stdlib.StdlibChecker #44BB99 {
2626
msgs : dict[str, MessageDefinitionTuple]
2727
name : str
2828
deprecated_arguments(method: str) -> tuple[tuple[int | None, str], ...]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
digraph "classes" {
2+
rankdir=BT
3+
charset="utf-8"
4+
"custom_colors.CheckerCollector" [color="red", fontcolor="black", label=<{CheckerCollector|checker1<br ALIGN="LEFT"/>checker2<br ALIGN="LEFT"/>checker3<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
5+
"pylint.extensions.check_elif.ElseifUsedChecker" [color="#44BB88", fontcolor="black", label=<{ElseifUsedChecker|msgs : dict<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>|leave_module(_: nodes.Module): None<br ALIGN="LEFT"/>process_tokens(tokens: list[TokenInfo]): None<br ALIGN="LEFT"/>visit_if(node: nodes.If): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
6+
"pylint.checkers.exceptions.ExceptionsChecker" [color="yellow", fontcolor="black", label=<{ExceptionsChecker|msgs : dict<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>options : tuple<br ALIGN="LEFT"/>|open(): None<br ALIGN="LEFT"/>visit_binop(node: nodes.BinOp): None<br ALIGN="LEFT"/>visit_compare(node: nodes.Compare): None<br ALIGN="LEFT"/>visit_raise(node: nodes.Raise): None<br ALIGN="LEFT"/>visit_tryexcept(node: nodes.TryExcept): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
7+
"pylint.checkers.stdlib.StdlibChecker" [color="yellow", fontcolor="black", label=<{StdlibChecker|msgs : dict[str, MessageDefinitionTuple]<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>|deprecated_arguments(method: str): tuple[tuple[int | None, str], ...]<br ALIGN="LEFT"/>deprecated_classes(module: str): Iterable[str]<br ALIGN="LEFT"/>deprecated_decorators(): Iterable[str]<br ALIGN="LEFT"/>deprecated_methods(): set[str]<br ALIGN="LEFT"/>visit_boolop(node: nodes.BoolOp): None<br ALIGN="LEFT"/>visit_call(node: nodes.Call): None<br ALIGN="LEFT"/>visit_functiondef(node: nodes.FunctionDef): None<br ALIGN="LEFT"/>visit_if(node: nodes.If): None<br ALIGN="LEFT"/>visit_ifexp(node: nodes.IfExp): None<br ALIGN="LEFT"/>visit_unaryop(node: nodes.UnaryOp): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
8+
"pylint.checkers.exceptions.ExceptionsChecker" -> "custom_colors.CheckerCollector" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="checker1", style="solid"];
9+
"pylint.checkers.stdlib.StdlibChecker" -> "custom_colors.CheckerCollector" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="checker3", style="solid"];
10+
"pylint.extensions.check_elif.ElseifUsedChecker" -> "custom_colors.CheckerCollector" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="checker2", style="solid"];
11+
}

tests/pyreverse/functional/class_diagrams/colorized_output/custom_colors.puml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class "CheckerCollector" as custom_colors.CheckerCollector #red {
55
checker2
66
checker3
77
}
8-
class "ElseifUsedChecker" as pylint.extensions.check_elif.ElseifUsedChecker #green {
8+
class "ElseifUsedChecker" as pylint.extensions.check_elif.ElseifUsedChecker #44BB88 {
99
msgs : dict
1010
name : str
1111
leave_module(_: nodes.Module) -> None
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[testoptions]
2-
output_formats=puml
3-
command_line_args=-S --colorized --max-color-depth=2 --color-palette=red,green,yellow
2+
output_formats=puml,dot
3+
command_line_args=-S --colorized --max-color-depth=2 --color-palette=red,#44BB88,yellow

0 commit comments

Comments
 (0)