Version: 9.15.0
CONNECTOR.py
Go to the documentation of this file.
1 # Copyright (C) 2006-2025 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 """
39 import traceback
40 from copy import copy
41 import weakref
42 
44  pass
45 
46 class CONNECTOR:
47 
48  def __init__(self):
49  self.connectionsconnections={}
50 
51  def Connect(self, object, channel, function, args):
52 
53  idx = id(object)
54  if idx in self.connectionsconnections:
55  channels = self.connectionsconnections[idx]
56  else:
57  channels = self.connectionsconnections[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.connectionsconnections[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.connectionsconnections[id(object)]
90  del channels[channel]
91  if not channels:
92  # the object has no more channels
93  del self.connectionsconnections[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.connectionsconnections[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 
120 def 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.SelfSelf=weakref.ref(callable.__self__)
129  self.FuncFunc=weakref.ref(callable.__func__)
130 
131  def __call__(self):
132  target=self.SelfSelf()
133  if not target:return None
134  func=self.FuncFunc()
135  if func:
136  return func.__get__(self.SelfSelf())
137 
138 _the_connector =CONNECTOR()
139 Connect = _the_connector.Connect
140 Emit = _the_connector.Emit
141 Disconnect = _the_connector.Disconnect
142 
143 if __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