具有复杂类型提示的 Pyreverse UML(Union、List,...)

Dro*_*ppi 5 python uml class-diagram pylint pyreverse

我正在尝试为使用 Unions 和 List 类型提示的类生成 UML 图。

一个例子是

from dataclasses import dataclass
from typing import Union   

@dataclass
class ClassA:
    name: str    

@dataclass
class ClassB:
    an_attribute: int    

@dataclass
class ClassC:
    my_class: Union[ClassA, ClassB]
Run Code Online (Sandbox Code Playgroud)

运行时pyreverse -ASmn stackoverflow_example.py -o png我获得一个未显示 classA 和 classB 用法的 UML:

具有三个未连接的类 A、B 和 C 的 UML 类图

如果我将代码替换ClassC

@dataclass
class ClassC:
    my_class: ClassA
Run Code Online (Sandbox Code Playgroud)

然后我得到一个更接近我的目标的 UML 描述: UML类图,有3个类A、B和C,C由A组成

但是,当然,这意味着当我分配某种类型时,我ClassBmy_class收到突出显示的警告,这正是它应该做的。我对应该如何工作的理解Union是我会得到这样的东西: 手动编辑的UML类图,有3个类A、B和C,C由A和B组成

该示例显示了 Union,但 List 和其他人也会有类似的行为。

有没有办法做到这一点,或者这是一个不应该这样做的设计?

Chr*_*phe 6

在 UML 中应该如何表示?

\n

根据PEP 484指定类型提示:

\n
\n

由 Union[T1, T2, ...] 分解的类型是所有类型 T1、T2 等的超类型,因此作为这些类型之一的成员的值对于由 Union[T1 注释的参数来说是可接受的,T2,...]。

\n
\n

但在 UML 中,这需要一种中间类型,因为只能有一个my_class成员:

\n

在此输入图像描述

\n

如何在pyreverse中获得它?

\n

看看pyreverse的不同选项,我们能做的并不多:

\n
    \n
  • -b您可以添加包含内置类型的选项。在这种情况下,您将看到所有类都继承自object,并且您将看到intstr 包括该类型的成员的组成。但Union仍然绝望地保持原样,并且没有显示出 PEP 484 所建议的任何内容。这表明pyreverse 不支持此功能。

    \n
  • \n
  • Pyreverse 显示了与 Union 完全相同的行为,就好像您添加了一个不存在的类型(例如xxxx,甚至是无意义的,例如xxx [1,2,yyy]):它指示源文件中的字符串,但不绘制相应的字符串对象。这强化了缺乏支持的印象。

    \n
  • \n
  • 在上次的经验中,我在pyreverse中将示例文件与typing.py包一起处理。它很好地识别了包之间的依赖关系。但工会仍然没有改变。

    \n
  • \n
  • 使用替代语法ClassA | ClassB会导致图表略有不同,因为类型信息被完全删除,但也没有显示组合。

    \n
  • \n
\n

我只能得出结论,这个工具似乎不支持联合的图形渲染。

\n

工会的解决办法?

\n

Union 是一个实用的功能,但不是非常面向对象:

\n
    \n
  • UML 没有直接支持它,你\xe2\x80\x99d 需要按照上面的解释来处理它。
  • \n
  • 联合将潜在不相关的类型组合在一起,这不利于多态编程。
  • \n
\n

幸运的是,有一个简单的替代方法:使 A 和 B 成为一个公共空类(例如 AB)的子类,然后创建my_class一个AB. Pyreverse 然后生成预期结果:

\n

在此输入图像描述

\n

  • 我可以确认“pyreverse”目前不支持这一点。从类型注释(例如 Union 或Optional)创建附加中间图节点不属于此工具的范围。 (4认同)
  • @Drooppi 目前我不知道如何仅从类型提示中仅显示两个组合箭头。这是因为,正如您已经注意到的,复杂类型提示尚未得到很好的支持。`pyreverse` 并不以严格的 UML 为目标,只要图表的意图是明确的即可。对于多重关联,目前实际上有一个开放的拉取请求:https://github.com/PyCQA/pylint/pull/6434 我已经在 GitHub 上针对其余案例打开了一个功能请求,但我不能保证什么时候会出现这种情况将实施:https://github.com/PyCQA/pylint/issues/6737 (2认同)