【问题标题】:It is possible to generate sequence diagram from python code?可以从python代码生成序列图吗?
【发布时间】:2017-12-27 13:04:46
【问题描述】:

我有大约 700 行代码。我必须写一个关于这段代码的小文档。在这个文档中,我计划有一个序列图来解释更多。像这样: 因为我有点懒,我想知道是否有工具可以从代码生成这个图表。我不想为此浪费整个周末。

有人有什么想法可以帮助我吗?

谢谢。

【问题讨论】:

标签: python sequence-diagram


【解决方案1】:

我也在搜索这个主题,发现以下有用: https://github.com/bereal/pyspy

它使用byteplay 修补字节码,您可以添加自己的回调函数来在每次调用之前和之后执行某些操作。类似于使用sys.settrace 编写分析器,但更简单。

好吧,我添加了一些修复作为 issue-cmets,因为我无法从这里正确使用 git。您的函数可以将 DLS 编写为文本,就像 PlantUMLZenUML... 所需要的那样,并使用它来生成您的图表。

【讨论】:

  • This question is OT here ("要求我们推荐或查找书籍、工具、软件库、教程或其他非现场资源的问题对于 Stack Overflow 来说是题外话,因为它们往往会吸引固执己见答案和垃圾邮件”),应该这样关闭。
  • @brunodesthuilliers:是的,我知道,但我必须承认,我也在 SO 中搜索推荐,当我找到答案时我很高兴...... :-)
【解决方案2】:

python 中的 Plantuml 可能会有所帮助。对于如何安装使用链接 PlantUML with python

文本文件应该是这样的:

Python -> HL : create
activate HL
HL -> LL : run
activate LL
LL -> SLI : exec
activate SLI
SLI --> LL
deactivate SLI
LL --> HL
deactivate LL
HL -> LL : push
activate LL
LL -> SLI : push
activate SLI
SLI --> LL
deactivate SLI
LL --> HL
deactivate LL
HL -> LL : run
activate LL
LL -> SLI : exec
activate SLI
SLI --> LL
deactivate SLI
LL --> HL
deactivate LL
HL -> LL : pop
activate LL
LL -> SLI : pop
activate SLI
SLI --> LL
deactivate SLI
LL --> HL
deactivate LL
HL --> Python
deactivate HL

python可以为此生成文本,例如可以在方法声明后添加。

print>>sd.txt, "->"+str(self.name)+":className"

这将附加到 sd.txt 并最终通过运行在项目目录中创建 png 文件:

python -m plantuml sd.txt

python-UML-sequence-diagram

【讨论】:

    【解决方案3】:

    这是一个简单的跟踪类和一个可以用它做什么的例子。 在要跟踪的每个函数的开头实例化类。 装饰器也可以按照相同的原理完成,但您必须相应地调整 python 框架解析

    class SequenceOn:
       autonumber = True
       init_done = False
    
    def __init__(self,participant=""):
    
        if not SequenceOn.init_done :
            #activate if requested only once
            if SequenceOn.autonumber: 
                print ("autonumber")
    
            SequenceOn.init_done = True
    
        #retrieve callee frame
        callee_frame = sys._getframe(1)
    
        #method/function name
        self.__funcName = callee_frame.f_code.co_name
    
        # look for a class name
        if 'self' in callee_frame.f_locals:
            self.__className = callee_frame.f_locals['self'].__class__.__name__
        else:
            self.__className = participant
    
        #retrieve the caller frame and class name of the caller
        caller_frame = sys._getframe(2)
    
        if 'self' in caller_frame.f_locals:
            self.__caller = caller_frame.f_locals['self'].__class__.__name__
        else:
            self.__caller = ""
    
        #print the plantuml message
        activate = "++" if self.__caller != self.__className else ""
        print (f'{self.__caller} -> {self.__className} {activate} :{self.__funcName}')
    
    
    def __del__(self):
        ''' print the return message upon destruction '''
        if self.__caller != self.__className:
            print (f'{self.__caller} <-- {self.__className} -- ')
    
    def note(self,msg):
        print (f'note over {self.__className}:{msg}')
    
    class SequenceOff:
        ''' empty class allowing to disable the trace by eg doing in the begining of a file:
    
        Seq = SequenceOn # enable sequence generation
        Seq = SequenceOff # disable sequence generation
    
        and using seq for tracing instead of SequenceOn
        '''
        def __init__(self,participant=""):
            pass
        def __call__(self,msg):
            pass
        def note(self,msg):
            pass
    

    在下面的示例代码中:

    if __name__ == "__main__":
    
    class B:
        def __init__(self):
            pass
    
        def funcB1(self):
            s = SequenceOn()
    
        def funcB2(self):
            s = SequenceOn()
            s.note("calling private method")
            self.__funcB22()
    
        def __funcB22(self):
            s = SequenceOn()
    
    class A:
        def __init__(self):
            pass
        def funcA(self):
    
            s = SequenceOn()
            b = B()
            b.funcB1()
            b.funcB2()
    
    # simple sequence
    a = A()
    a.funcA()
    

    你得到:

    autonumber
     -> A ++ :funcA
    A -> B ++ :funcB1
    A <-- B --
    A -> B ++ :funcB2
    note over B:calling private method
    B -> B  :__funcB22
    A <-- B --
     <-- A --
    

    这会产生:

    【讨论】:

      猜你喜欢
      • 2022-08-17
      • 1970-01-01
      • 2013-12-13
      • 1970-01-01
      • 2015-09-09
      • 2013-06-23
      • 2012-01-03
      • 2012-04-06
      • 2015-06-16
      相关资源
      最近更新 更多