It is possible to generate sequence diagram from python code?
Asked Answered
R

3

16

I have about 700 lines of code. I have to write a little doc about this code. In this doc, I plan to have a sequence diagram to explain a bit more. something like this: enter image description here Since Iam a bit lazy, I would like to know if there is a tool to generate this diagram from code. I don't want to lose my entire weekend doing this.

Do some have an idea that could help me?

Thanks.

Randeerandel answered 21/7, 2017 at 12:58 Comment(1)
Possibly offtopic for SO, but checkout networkx networkx.readthedocs.io/en/stable/index.html or if you want. Also workflow managers like ruffus ruffus.readthedocs.io/en/latest or snakemake snakemake.readthedocs.io/en/stablePlenary
U
3

I was searching for this topic too and found the following usefull: https://github.com/bereal/pyspy

It patches the bytecode using byteplay and you can add your own callback-functions to do something before each call and after each. Similar to writting a profiler using sys.settrace but easier.

Well, I added some fixes as issue-comments because I was not able to use git properly from here. Your functions may write DLS as text, like is needed by PlantUML or ZenUML... and use it to generate your diagram.

Unquestionable answered 15/1, 2019 at 12:30 Comment(2)
This question is OT here ("Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam") and should have been closed as such.Landaulet
@brunodesthuilliers: yes, I know, but I must admid, that I search for recommendation in SO too and I'm happy when I found an answer... :-)Unquestionable
B
3

The Plantuml in python could be helpful. For how to install use link PlantUML with python

Text file should be like so:

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

enter image description here

It is possible to generate the text by python for this purpose, for example, you can add after the method declaration.

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

This will append to sd.txt and finally create png file in the project directory by running:

python -m plantuml sd.txt

python-UML-sequence-diagram

Beneficial answered 1/2, 2019 at 13:53 Comment(1)
Something to keep in mind is that it will send your data to an external server. I tested it locally with test data and it works, I just wouldn't use this specific one for company "secret stuff".Contredanse
K
3

Here is a simple tracing class and an example of what can be done with it. instantiate the class at the beginning of each function you want to trace. A decorator could also be done on the same principle but you would have to adapt the python frame parsing accordingly

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

On the below sample code:

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()

You get:

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

Which generates: enter image description here

Kunkel answered 30/3, 2020 at 12:57 Comment(1)
Thanks for your solution. But may I know if there is a way to generate sequence diagrams from static python source code without altering it?Muff

© 2022 - 2024 — McMap. All rights reserved.