• plantUML 实操


    工具:

    在线编译工具

    https://www.planttext.com/

    自动检测类并输出uml文件脚本

     1 def genUML(cs,outfile="d://test.uml"):
     2 
     3     ignoredNames=['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__','__dict__','__module__','__weakref__']
     4     
     5     s=''
     6     s+='@startuml'
     7     print(__file__.split('\'))
     8     for c in cs:
     9         cls=eval(c)
    10         for base in cls.__bases__:
    11             s+=f'
    {base.__name__} <|-down- {cls.__name__}: Inheritance'
    12         s+=f'
    class {cls.__name__} {{'
    13         for name in list(c for c in dir(cls)):
    14             if(name in ignoredNames):
    15                 continue
    16             k=getattr(cls,name)
    17             if(name.startswith('_')):
    18                 s+='
      -'
    19             else:
    20                 s+='
      +'
    21             if(k.__class__.__name__ not in ['function','method']):
    22                 s+=f'{k.__class__.__name__} {name}'
    23             else:
    24                 s+=f'{name}()'
    25         s+='
    }'
    26     s+='
    @enduml'
    27     print(s)    
    28     with open(outfile,'w') as f:
    29         f.write(s)
    30     return s
    31     pass
    32 
    33 #获取当前可视的所有类,简单过滤
    34 cs=list(c for c in dir() if(not c.startswith('_') and c[0].isupper())) 
    35 
    36 #生成
    37 genUML(cs)
    38 
    39 #copy uml代码到网站并生成
    View Code

    实例

      1 import threading
      2 import socket
      3 import time
      4 import json
      5 threadLock = threading.Lock()
      6 
      7 class D_Print(object): 
      8     def __call__(self,func):  
      9         def _call(*args,**kw):     
     10             output=None
     11             error=None
     12             
     13             print(func.__name__)
     14             try:
     15                 output=func(*args,**kw) # 被装饰的函数
     16             except Exception as e:
     17                 error=e
     18             
     19             self.saveAs(args=args,
     20                       kw=kw,
     21                       output=output,
     22                       error=error)
     23             
     24             if(error):
     25                 raise error
     26             else:
     27                 return output
     28             
     29         return _call  
     30     
     31     def saveAs(self,*,args,kw,output,error): # 演示
     32         # print(f'Debug get args,kw={args},{kw}')
     33         # print(f'Debug get output={output}')
     34         # print(f'Debug get error={error}')
     35         pass
     36 
     37 
     38 class ThreadProxy():
     39     @staticmethod
     40     def create(target=None,args=[],name=''):
     41         if(target):
     42             thread = threading.Thread(target=target,args=args)
     43             thread.setDaemon(True)
     44             thread.setName(name)
     45             thread.start()
     46             return thread
     47         else:
     48             return None
     49         pass
     50     @staticmethod
     51     def printThreads():
     52         threadLock.acquire()
     53         count=0
     54         print('-----Printing----')
     55         for t in threading.enumerate():
     56             count+=1
     57             print(f'|{count:02d}:Thread={t.name}')
     58         print('--------End------')
     59         threadLock.release()
     60         pass
     61     pass
     62 
     63 class CXTMsg():
     64     SPEC=b'CXTMSG'
     65     m_A={'key':'A','action':'do A'}
     66     m_B={'key':'B','action':'do B'}
     67     m_M={'key':'m','action':'do m'}
     68     pass
     69 class CXTMsgBase():
     70     SPEC=b'CXTMSG'
     71     @classmethod
     72     def readMessage(cls,msgBytes):
     73         mb=msgBytes
     74         msg=None
     75         idx=msgBytes.find(cls.SPEC)
     76         print('readMessage idx',idx)
     77         if(idx<0):
     78             print(f'Discard {len(msgBytes)}. {msgBytes}')
     79             msgBytes=b''
     80             return msg,msgBytes
     81         print(msgBytes)
     82         try:
     83             print('Parsing')
     84             msgBytes=msgBytes[idx:]
     85             head=msgBytes[:len(CXTMsgBase.SPEC)].decode('utf-8')
     86             print('head',head)
     87             msgBytes=msgBytes[len(CXTMsgBase.SPEC):]
     88             LoL=int(msgBytes[:2].decode('utf-8'),16)
     89             print('LoL',LoL)
     90             msgBytes=msgBytes[2:]
     91             LoV=int(msgBytes[:LoL].decode('utf-8'),16)
     92             print('LoV',LoV)
     93             msgBytes=msgBytes[LoL:]
     94             value=msgBytes[:LoV]
     95             print('value',value)
     96             
     97             msg=cls.fromBytes(value)
     98             
     99             msgBytes=msgBytes[LoV:]
    100             print(msg)
    101             return msg,msgBytes
    102         except Exception as e:
    103             print('readMessage Parsing Error=',e)
    104             msg=None
    105             msgBytes=mb
    106             return msg,msgBytes
    107             pass
    108         pass
    109     @classmethod
    110     def packMessage(cls,msg):
    111         head=cls.SPEC
    112         value=cls.toBytes(msg)
    113         LoV=("%X"%len(value)).encode('utf-8') # 16进制
    114         #LoV=("%X"%1024*10).encode('utf-8') #almost no infi
    115         LoL=("%02x"%(len(LoV))).encode('utf-8') #16进制
    116         # print(LoV)
    117         # print(len(LoL))
    118         return head+LoL+LoV+value
    119         pass
    120     @staticmethod
    121     def toBytes(msg,encoding='utf-8',errors='ignore'):
    122         return json.dumps(msg).encode(encoding='utf-8')
    123         pass
    124     @staticmethod
    125     def fromBytes(msgBytes,encoding='utf-8',error='ignore'):
    126         '''msgBytes or msgStr'''
    127         msgStr=msgBytes.decode(encoding=encoding,errors=error)
    128         return json.loads(msgStr)
    129         pass
    130     pass
    131 class M_Notify(CXTMsgBase):
    132     def __init__(self):
    133         pass
    134     pass
    135     
    136 class ComBase():
    137     def __init__():
    138         self.name='Base'
    139         self._msgStack=[]
    140         pass
    141     @property
    142     def msgStack(self):
    143         return self._msgStack
    144     @msgStack.setter
    145     def msgStack(self,value):
    146         threadLock.acquire()
    147         print(self.name,'msgStack Update',value)
    148         self._msgStack=value
    149         threadLock.release()
    150         pass
    151     def note(self,*args):
    152         if(self.name=='server'):
    153             print(f'*[{self}]->',('%s'*len(args))%(args),flush=True)
    154         else:
    155             print(f' [{self}]->',('%s'*len(args))%(args),flush=True)
    156         pass
    157     def __str__(self):
    158         return self.name
    159         pass
    160     def recvLoop(self,sock):
    161         """
    162         消息处理
    163         """
    164         try:
    165             recvBuff=b''
    166             while True:
    167                 recvBuff+= sock.recv(1024)
    168                 if(len(recvBuff)>0):
    169                     print('recvBuff',recvBuff)
    170                     recvBuff=self.readMessage(recvBuff)
    171                 #self.recvLoopBody(sock)
    172         except ConnectionResetError as e:
    173             self.note(self,type(e).__name__,f'={e}')
    174         except Exception as e:
    175             self.note(self,type(e).__name__,f'={e}')
    176         finally:
    177             sock.close()
    178             self.onRecvClosed(sock)
    179     def readMessage(self,recvBuff):
    180         while(True):
    181             msg,recvBuff=CXTMsgBase.readMessage(recvBuff)
    182             print(msg,recvBuff)
    183             if(msg!=None):
    184                 print('update msgStack')
    185                 self.msgStack+=[msg]
    186             else:
    187                 break
    188             pass
    189         return recvBuff
    190         pass
    191     # def recvLoopBody(self,sock):
    192         # bytes = sock.recv(1024)
    193         # #name=sock.getpeername()
    194         # if(bytes==b''):
    195             # raise Exception('Empty Msg Mean Closed!')
    196         # self.note(f"消息:", self._bytes2Str(bytes))
    197         pass 
    198     def msgLoop(self):
    199         """
    200         消息处理
    201         """
    202         try:
    203             while True:
    204                 self.msgLoopBody()
    205                 time.sleep(10)
    206         except Exception as e:
    207             self.note(self,type(e).__name__,f'={e}')
    208         finally:
    209             print('msgLoop End')
    210         pass
    211     def msgLoopBody(self):
    212         print(self.name,'msgStack',self.msgStack)
    213         msg=None
    214         threadLock.acquire()
    215         if(len(self.msgStack)>0):
    216             msg=self.msgStack.pop(0)
    217         threadLock.release()
    218         if(msg):
    219             print(f'Done {msg}')
    220         pass
    221     def sendMsg(self):
    222         pass
    223     def onRecvClosed(self,sock):
    224         #Default Do Nothing
    225         pass
    226     # def message2json(self):
    227         # pass
    228     # def json2message(self):
    229         # pass
    230     def _bytes2Str(self,b,encoding='utf8',errors='ignore'):
    231         return b.decode(encoding=encoding,errors=errors)
    232         pass
    233     def _str2Bytes(self,s,encoding='utf8',errors='ignore'):
    234         if(type(s) is bytes):
    235             return s
    236         else:
    237             return s.encode(encoding=encoding,errors=errors)
    238         pass
    239     pass
    240 class ClientApp(ComBase):
    241     
    242     @D_Print()
    243     def __init__(self,name='client',address = ('127.0.0.1', 8712)):
    244         self.name=name
    245         self.raddress=address
    246         self.serverSocket=None
    247         self.msgStack=[]
    248         pass    
    249     def start(self):
    250         self.serverSocket = socket.socket()  # 创建 socket 对象
    251         self.serverSocket.connect(self.raddress)
    252         #self.serverSocket.send("连接了".encode('utf8'))
    253         
    254         ThreadProxy.create(target=self.recvLoop
    255                             ,args=[self.serverSocket]
    256                             ,name='Client recvThread')
    257         
    258         ThreadProxy.create(target=self.msgLoop
    259                             ,args=[]
    260                             ,name='Client msgThread')                    
    261         return self
    262         pass
    263     def send(self,cmd):
    264         self.serverSocket.send(self._str2Bytes(cmd))
    265         pass
    266     def sendMsg(self,msg):
    267         msgBytes=CXTMsgBase.packMessage(msg)
    268         self.serverSocket.send(msgBytes)
    269     def close(self,sock=None):
    270         if(not sock):
    271             sock=self.serverSocket
    272         
    273         #threadLock.acquire()
    274         sock.close()
    275         del sock
    276         #threadLock.release()
    277         pass
    278     pass
    279 
    280 class ServerApp(ComBase):
    281     @D_Print()
    282     def __init__(self,name='server',address = ('127.0.0.1', 8712)):
    283         self.name=name
    284         self.address=address
    285         self.serverSocket=None
    286         self.handlerGroup=[]
    287         self.msgStack=[]
    288         pass
    289     def start(self):
    290         #startListener
    291         self.serverSocket = socket.socket(
    292                     socket.AF_INET, 
    293                     socket.SOCK_STREAM)  # 创建 socket 对象
    294         self.serverSocket.bind(self.address)
    295         self.serverSocket.listen(5)  # 最大等待数(有很多人理解为最大连接数,其实是错误的)
    296         
    297         ThreadProxy.create(target=self.acceptLoop
    298                             ,args=[]
    299                             ,name='Server acceptThread')
    300                             
    301         ThreadProxy.create(target=self.msgLoop
    302                             ,args=[]
    303                             ,name='Server msgThread')
    304                             
    305         return self
    306         pass
    307     def acceptLoop(self):
    308         """
    309         接收新连接
    310         """
    311         while True:
    312             self.note(f"等待客户端连接...")
    313             clientSocket, _ = self.serverSocket.accept()  # 阻塞,等待客户端连接
    314             self.onClientAccepted(clientSocket)
    315             pass
    316         pass
    317     def onClientAccepted(self,clientSocket):
    318         # # 给每个客户端创建一个独立的线程进行管理
    319         # thread = threading.Thread(target=cls.recvLoop, args=(clientSocket,))
    320         # # 设置成守护线程
    321         # thread.setDaemon(True)
    322         # thread.start()
    323         self.registClient(clientSocket)
    324         
    325         ThreadProxy.create(target=self.recvLoop
    326                             ,args=[clientSocket]
    327                             ,name='Server RecvThread')
    328         pass
    329     def registClient(self,clientSocket):
    330         self.note(f"Client Registing")
    331         threadLock.acquire()
    332         
    333         self.handlerGroup.append(clientSocket)
    334         
    335         name=clientSocket.getpeername()
    336         self.note(f"{name} Connected")
    337         self.note(f"Now Client Count={len(self.handlerGroup)}")
    338         
    339         threadLock.release()
    340         self.note(f"Client Registed")
    341         pass
    342     def onRecvClosed(self,sock):
    343         self.onClientClosed(sock)
    344         pass
    345     def onClientClosed(self,clientSocket):
    346         threadLock.acquire()
    347         
    348         idx=self.handlerGroup.index(clientSocket)
    349         self.handlerGroup.remove(clientSocket)
    350         
    351         self.note(f"client {idx} left")
    352         self.note(f"Now Client Count={len(self.handlerGroup)}")
    353         
    354         threadLock.release()
    355         pass 
    356     def send(self,clientIdx,cmd):
    357         self.note('Sending...')
    358         c=self.getClientSocket(clientIdx)
    359         if(c):
    360             c.send(self._str2Bytes(cmd))
    361         else:
    362             self.note('send error')
    363             pass
    364         pass
    365     def sendMsg(self,clientIdx,msg):
    366         self.note('Sending...')
    367         c=self.getClientSocket(clientIdx)
    368         if(c):
    369             msgBytes=CXTMsgBase.packMessage(msg)
    370             c.send(msgBytes)
    371         else:
    372             self.note('send error')
    373             pass
    374     def getClientSocket(self,idx):
    375         try:
    376             return self.handlerGroup[idx]
    377         except:
    378             print('getClientSocket error')
    379             return None
    380         pass
    381     def close(self,clientIdx):
    382         self.note('Client Closeing...')
    383         c=self.getClientSocket(clientIdx)
    384         if(c):
    385             threadLock.acquire()
    386             c.close()
    387             threadLock.release()
    388         else:
    389             self.note('close error')
    390             pass
    391         pass
    392     def broadcast(self,s):
    393         for sock in self.handlerGroup:
    394             threadLock.acquire()
    395             try:
    396                 sock.send(self._str2Bytes(s))
    397             except:
    398                 self.note('BC Error.')
    399                 pass
    400             threadLock.release()
    401         pass
    402     pass
    403 
    404 def genUML(cs,outfile="d://test.uml"):
    405 
    406     ignoredNames=['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__','__dict__','__module__','__weakref__']
    407     
    408     s=''
    409     s+='@startuml'
    410     print(__file__.split('\'))
    411     for c in cs:
    412         cls=eval(c)
    413         for base in cls.__bases__:
    414             s+=f'
    {base.__name__} <|-down- {cls.__name__}: Inheritance'
    415         s+=f'
    class {cls.__name__} {{'
    416         for name in list(c for c in dir(cls)):
    417             if(name in ignoredNames):
    418                 continue
    419             k=getattr(cls,name)
    420             if(name.startswith('_')):
    421                 s+='
      -'
    422             else:
    423                 s+='
      +'
    424             if(k.__class__.__name__ not in ['function','method']):
    425                 s+=f'{k.__class__.__name__} {name}'
    426             else:
    427                 s+=f'{name}()'
    428         s+='
    }'
    429     s+='
    @enduml'
    430     print(s)    
    431     with open(outfile,'w') as f:
    432         f.write(s)
    433     return s
    434     pass
    435 
    436 #获取当前可视的所有类,简单过滤
    437 cs=list(c for c in dir() if(not c.startswith('_') and c[0].isupper())) 
    438 
    439 #生成
    440 genUML(cs)
    441 
    442 #copy uml代码到网站并生成
    实例

    输出

    @startuml
    object <|-down- CXTMsg: Inheritance
    class CXTMsg {
      +bytes SPEC
      +dict m_A
      +dict m_B
      +dict m_M
    }
    object <|-down- CXTMsgBase: Inheritance
    class CXTMsgBase {
      +bytes SPEC
      +fromBytes()
      +packMessage()
      +readMessage()
      +toBytes()
    }
    ComBase <|-down- ClientApp: Inheritance
    class ClientApp {
      -_bytes2Str()
      -_str2Bytes()
      +close()
      +msgLoop()
      +msgLoopBody()
      +property msgStack
      +note()
      +onRecvClosed()
      +readMessage()
      +recvLoop()
      +send()
      +sendMsg()
      +start()
    }
    object <|-down- ComBase: Inheritance
    class ComBase {
      -_bytes2Str()
      -_str2Bytes()
      +msgLoop()
      +msgLoopBody()
      +property msgStack
      +note()
      +onRecvClosed()
      +readMessage()
      +recvLoop()
      +sendMsg()
    }
    object <|-down- D_Print: Inheritance
    class D_Print {
      -__call__()
      +saveAs()
    }
    CXTMsgBase <|-down- M_Notify: Inheritance
    class M_Notify {
      +bytes SPEC
      +fromBytes()
      +packMessage()
      +readMessage()
      +toBytes()
    }
    ComBase <|-down- ServerApp: Inheritance
    class ServerApp {
      -_bytes2Str()
      -_str2Bytes()
      +acceptLoop()
      +broadcast()
      +close()
      +getClientSocket()
      +msgLoop()
      +msgLoopBody()
      +property msgStack
      +note()
      +onClientAccepted()
      +onClientClosed()
      +onRecvClosed()
      +readMessage()
      +recvLoop()
      +registClient()
      +send()
      +sendMsg()
      +start()
    }
    object <|-down- ThreadProxy: Inheritance
    class ThreadProxy {
      +create()
      +printThreads()
    }
    @enduml
    uml

    输出

  • 相关阅读:
    EffectiveC++ 第6章 继承与面向对象设计
    关于并查集的路径压缩(Path Compress)优化
    EffectiveC++ 第5章 实现
    linux 中ls命令文件夹颜色修改
    linux中发出“滴”的怪声的解决方案
    java 常量池技术
    linux与window文件路径问题
    struts上传文件大小超过配置值的问题
    MDC介绍 -- 一种多线程下日志管理实践方式
    java单例模式的二种正确实现
  • 原文地址:https://www.cnblogs.com/xiaoboz/p/11770851.html
Copyright © 2020-2023  润新知