plantUML 实操

点点圈 提交于 2019-12-03 02:12:58

工具:

在线编译工具

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'\n{base.__name__} <|-down- {cls.__name__}: Inheritance'
12         s+=f'\nclass {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+='\n  -'
19             else:
20                 s+='\n  +'
21             if(k.__class__.__name__ not in ['function','method']):
22                 s+=f'{k.__class__.__name__} {name}'
23             else:
24                 s+=f'{name}()'
25         s+='\n}'
26     s+='\n@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'\n{base.__name__} <|-down- {cls.__name__}: Inheritance'
415         s+=f'\nclass {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+='\n  -'
422             else:
423                 s+='\n  +'
424             if(k.__class__.__name__ not in ['function','method']):
425                 s+=f'{k.__class__.__name__} {name}'
426             else:
427                 s+=f'{name}()'
428         s+='\n}'
429     s+='\n@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

输出

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!