diff --git a/doc/whatsnew/fragments/9014.bugfix b/doc/whatsnew/fragments/9014.bugfix new file mode 100644 index 0000000000..a461855e25 --- /dev/null +++ b/doc/whatsnew/fragments/9014.bugfix @@ -0,0 +1,3 @@ +Don't add `Optional` to `|` annotations with `None` in Pyreverse diagrams. + +Closes #9014 diff --git a/pylint/pyreverse/utils.py b/pylint/pyreverse/utils.py index 6294773b2c..cf2a0ab6a7 100644 --- a/pylint/pyreverse/utils.py +++ b/pylint/pyreverse/utils.py @@ -194,14 +194,22 @@ def get_annotation( default = "" label = get_annotation_label(ann) - if ann: - label = ( - rf"Optional[{label}]" - if getattr(default, "value", "value") is None - and not label.startswith("Optional") - else label + + if ( + ann + and getattr(default, "value", "value") is None + and not label.startswith("Optional") + and ( + not isinstance(ann, nodes.BinOp) + or not any( + isinstance(child, nodes.Const) and child.value is None + for child in ann.get_children() + ) ) - if label: + ): + label = rf"Optional[{label}]" + + if label and ann: ann.name = label return ann diff --git a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.dot b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.dot index 94c242ccfc..6b0287c4a4 100644 --- a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.dot +++ b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.dot @@ -2,5 +2,5 @@ digraph "classes" { rankdir=BT charset="utf-8" "attributes_annotation.Dummy" [color="black", fontcolor="black", label=<{Dummy|
|}>, shape="record", style="solid"]; -"attributes_annotation.Dummy2" [color="black", fontcolor="black", label=<{Dummy2|alternative_union_syntax : str \| int
class_attr : list[Dummy]
optional : Optional[Dummy]
param : str
union : Union[int, str]
|}>, shape="record", style="solid"]; +"attributes_annotation.Dummy2" [color="black", fontcolor="black", label=<{Dummy2|alternative_optional : int \| None
alternative_optional_swapped : None \| int
alternative_union_syntax : str \| int
class_attr : list[Dummy]
optional : Optional[Dummy]
optional_union : Optional[int \| str]
param : str
union : Union[int, str]
|}>, shape="record", style="solid"]; } diff --git a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.mmd b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.mmd index 9f0b3d761c..aff946e7a8 100644 --- a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.mmd +++ b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.mmd @@ -2,9 +2,12 @@ classDiagram class Dummy { } class Dummy2 { + alternative_optional : int | None + alternative_optional_swapped : None | int alternative_union_syntax : str | int class_attr : list[Dummy] optional : Optional[Dummy] + optional_union : Optional[int | str] param : str union : Union[int, str] } diff --git a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.puml b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.puml index 1120832209..65bbb3755a 100644 --- a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.puml +++ b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.puml @@ -3,9 +3,12 @@ set namespaceSeparator none class "Dummy" as attributes_annotation.Dummy { } class "Dummy2" as attributes_annotation.Dummy2 { + alternative_optional : int | None + alternative_optional_swapped : None | int alternative_union_syntax : str | int class_attr : list[Dummy] optional : Optional[Dummy] + optional_union : Optional[int | str] param : str union : Union[int, str] } diff --git a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.py b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.py index d4fa931f51..3a4f52b4e6 100644 --- a/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.py +++ b/tests/pyreverse/functional/class_diagrams/annotations/attributes_annotation.py @@ -16,3 +16,6 @@ def __init__(self, param: str) -> None: self.union: Union[int, str] = "" self.alternative_union_syntax: str | int = 0 self.optional: Optional[Dummy] = None + self.alternative_optional: int | None = None + self.alternative_optional_swapped: None | int = None + self.optional_union: int | str = None