Version: 9.16.0
CONNECTOR.py
Go to the documentation of this file.
1# Copyright (C) 2006-2026 CEA, EDF
2#
3# This library is free software; you can redistribute it and/or
4# modify it under the terms of the GNU Lesser General Public
5# License as published by the Free Software Foundation; either
6# version 2.1 of the License, or (at your option) any later version.
7#
8# This library is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11# Lesser General Public License for more details.
12#
13# You should have received a copy of the GNU Lesser General Public
14# License along with this library; if not, write to the Free Software
15# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16#
17# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18#
19
20# -*- coding: iso-8859-15 -*-
21#
22"""
23 La classe CONNECTOR sert à enregistrer les observateurs d'objets et à délivrer
24 les messages émis à ces objets.
25
26 Le principe général est le suivant : un objet (subscriber) s'enregistre aupres du
27 connecteur global (theconnector) pour observer un objet emetteur de messages (publisher)
28 sur un canal donné (channel). Il demande à etre notifie par appel d'une fonction (listener).
29 La séquence est donc :
30
31 - enregistrement du subscriber pour le publisher : theconnector.Connect(publisher,channel,listener,args)
32 - émission du message par le publisher : theconnector.Emit(publisher,channel,cargs)
33
34 args et cargs sont des tuples contenant les arguments de la fonction listener qui sera appelée
35 comme suit::
36
37 listener(cargs+args)
38"""
39import traceback
40from copy import copy
41import weakref
42
43class ConnectorError(Exception):
44 pass
45
47
48 def __init__(self):
50
51 def Connect(self, object, channel, function, args):
52
53 idx = id(object)
54 if idx in self.connections:
55 channels = self.connections[idx]
56 else:
57 channels = self.connections[idx] = {}
58
59 if channel in channels:
60 receivers = channels[channel]
61 else:
62 receivers = channels[channel] = []
63
64 for funct,fargs in receivers[:]:
65 if funct() is None:
66 receivers.remove((funct,fargs))
67 elif (function,args) == (funct(),fargs):
68 receivers.remove((funct,fargs))
69
70 receivers.append((ref(function),args))
71
72
73
74 def Disconnect(self, object, channel, function, args):
75 try:
76 receivers = self.connections[id(object)][channel]
77 except KeyError:
78 raise ConnectorError('no receivers for channel %s of %s' % (channel, object))
79
80 for funct,fargs in receivers[:]:
81 if funct() is None:
82 receivers.remove((funct,fargs))
83
84 for funct,fargs in receivers:
85 if (function,args) == (funct(),fargs):
86 receivers.remove((funct,fargs))
87 if not receivers:
88 # the list of receivers is empty now, remove the channel
89 channels = self.connections[id(object)]
90 del channels[channel]
91 if not channels:
92 # the object has no more channels
93 del self.connections[id(object)]
94 return
95
96 raise ConnectorError('receiver %s%s is not connected to channel %s of %s' \
97 % (function, args, channel, object))
98
99
100 def Emit(self, object, channel, *args):
101
102 try:
103 receivers = self.connections[id(object)][channel]
104 except KeyError:
105 return
106
109 for rfunc, fargs in copy(receivers):
110 try:
111 func=rfunc()
112 if func:
113 func(*args + fargs)
114 else:
115 # Le receveur a disparu
116 if (rfunc,fargs) in receivers:receivers.remove((rfunc,fargs))
117 except:
118 traceback.print_exc()
119
120def ref(target,callback=None):
121 if hasattr(target,"im_self"):
122 return BoundMethodWeakref(target)
123 else:
124 return weakref.ref(target,callback)
125
127 def __init__(self,callable):
128 self.Self=weakref.ref(callable.__self__)
129 self.Func=weakref.ref(callable.__func__)
130
131 def __call__(self):
132 target=self.Self()
133 if not target:return None
134 func=self.Func()
135 if func:
136 return func.__get__(self.Self())
137
138_the_connector =CONNECTOR()
139Connect = _the_connector.Connect
140Emit = _the_connector.Emit
141Disconnect = _the_connector.Disconnect
142
143if __name__ == "__main__":
144 class A:pass
145 class B:
146 def add(self,a):
147 print("add",self,a)
148 def __del__(self):
149 print("__del__",self)
150
151 def f(a):
152 print(f,a)
153 print("a=A()")
154 a=A()
155 print("b=B()")
156 b=B()
157 print("c=B()")
158 c=B()
159 Connect(a,"add",b.add,())
160 Connect(a,"add",b.add,())
161 Connect(a,"add",c.add,())
162 Connect(a,"add",f,())
163 Emit(a,"add",1)
164 print("del b")
165 del b
166 Emit(a,"add",1)
167 print("del f")
168 del f
169 Emit(a,"add",1)
170 Disconnect(a,"add",c.add,())
171 Emit(a,"add",1)
172
173
def __del__(self)
Definition: CONNECTOR.py:148
def add(self, a)
Definition: CONNECTOR.py:146
def __init__(self, callable)
Definition: CONNECTOR.py:127
def Disconnect(self, object, channel, function, args)
Definition: CONNECTOR.py:74
def Emit(self, object, channel, *args)
Definition: CONNECTOR.py:100
def Connect(self, object, channel, function, args)
Definition: CONNECTOR.py:51
def ref(target, callback=None)
Definition: CONNECTOR.py:120