Revisão | 4d54ef32a3a7df5aae647507921265d131597412 (tree) |
---|---|
Hora | 2012-02-15 19:11:12 |
Autor | bijoux |
Commiter | bijoux |
Fixed recursive problem between Rule and Terminal
@@ -245,9 +245,13 @@ | ||
245 | 245 | self.xlabel = self._config['xlabel'] |
246 | 246 | self.ylabel = self._config['ylabel'] |
247 | 247 | |
248 | +class BasePlotPanel(Panel): | |
249 | + def layout(self): | |
250 | + Embed(self,BasePlot,name='result').pack() | |
251 | + | |
248 | 252 | class ScalarTable(Logic): |
249 | 253 | value = Terminal() |
250 | - format = Terminal('-+') | |
254 | + format = Terminal('-') | |
251 | 255 | @rule('value') |
252 | 256 | def result(self): |
253 | 257 | if self.value is None: return (array([0.,1.]),array([0.,1.])) |
@@ -5,6 +5,9 @@ | ||
5 | 5 | |
6 | 6 | # class ConcreteTerminal(object) |
7 | 7 | |
8 | +#TRACE = True | |
9 | +TRACE = False | |
10 | + | |
8 | 11 | class _PortException(Exception): |
9 | 12 | def __init__(self, value): |
10 | 13 | self.value = value |
@@ -62,22 +65,31 @@ | ||
62 | 65 | ''' |
63 | 66 | def __init__(self,init_value=None): |
64 | 67 | self.init_value = init_value |
65 | - self.name = None # 最初にset/get/linkが呼び出されたときにオーナーを検索して取得 | |
68 | + self.name = None # 最初にset/get/linkが呼び出されたときにオーナーを検索して取得 | |
69 | + self.from_rule = None | |
66 | 70 | def __get__(self, owner, ownertype): |
67 | - if owner == None: | |
68 | - return self | |
69 | - else: | |
70 | - attr = self.get_attribute(owner) | |
71 | - # attr.node.getlog[attr] = None # get 参照したことを対象の node.getlog へ記録 | |
72 | - attr.node.notify('get') | |
73 | - return attr.node.value | |
71 | + if owner == None: return self | |
72 | + attr = self.get_attribute(owner) | |
73 | + # | |
74 | + # set イベント処理中には get 参照されてもイベントは発行せずに set された内容を返す | |
75 | + # | |
76 | + try: self.__set_event | |
77 | + except AttributeError: pass | |
78 | + else: return attr.node.value | |
79 | +# attr.node.getlog[attr] = None # get 参照したことを対象の node.getlog へ記録 | |
80 | + if TRACE: print '= get = %s.%s' % (owner.__class__.__name__,self.name) | |
81 | + attr.node.notify('get') | |
82 | + return attr.node.value | |
74 | 83 | def __set__(self, owner, value): |
75 | 84 | node = self.get_attribute(owner).node |
76 | 85 | node.value = value |
77 | 86 | node.getlog.clear() # node を変更したので node.getlog を消去 |
87 | + if TRACE: print '= set = %s.%s' % (owner.__class__.__name__,self.name) | |
78 | 88 | node.notify('set') |
79 | 89 | def notify(self, attr, event): |
80 | 90 | if not event == 'set': return |
91 | + self.__set_event = True | |
92 | + if TRACE: print '- set -> %s.%s' % (attr.owner().__class__.__name__,self.name) | |
81 | 93 | owner = attr.owner() |
82 | 94 | # |
83 | 95 | # 依存関係のある rule を起動 |
@@ -88,10 +100,19 @@ | ||
88 | 100 | term = attr.terminal() |
89 | 101 | for name in term.dependency: # 未更新の Terminal がひとつもなければルールを実行する |
90 | 102 | if name == self.name: # 1つでも自身に依存していたらルールを実行可能か評価する |
91 | - for name in term.dependency: # 未更新の依存 Terminal がひとつでも見つかればルールを実行しない | |
92 | - if attr in terminal(owner,name).get_attribute(owner).node.getlog: break # ログに attr が見つかれば未更新 | |
103 | + for myname in term.dependency: # 未更新の依存 Terminal がひとつでも見つかればルールを実行しない | |
104 | + if TRACE: print '[%s]' % myname, | |
105 | + if attr in terminal(owner,myname).get_attribute(owner).node.getlog: | |
106 | + if TRACE: print 'not modified' | |
107 | + break # ログに attr が見つかれば未更新 | |
93 | 108 | else: # break で脱出しなかった場合 |
94 | - if not len(attr.terminal().dependency) == 0: term.notify(attr,'get') # かつ依存関係が空()でない場合にはルールを実行する | |
109 | + if not len(attr.terminal().dependency) == 0: | |
110 | + if TRACE: print '\n%s.%s - get ->' % (attr.owner().__class__.__name__,self.name) | |
111 | + term.notify(attr,'get') # かつ依存関係が空()でない場合にはルールを実行する | |
112 | +# if TRACE: print '\n%s.%s - get ->' % (attr.owner().__class__.__name__,self.name) | |
113 | +# term.notify(attr,'get') | |
114 | + try: del self.__set_event | |
115 | + except AttributeError: pass | |
95 | 116 | def get_name(self, owner): # オーナーインスタンスからの参照名を取得する |
96 | 117 | if self.name == None: # オーナーインスタンスが生成されてから最初に参照されたときには名称探索をする |
97 | 118 | # 呼び出しのコンテキストから、オーナーインスタンスにオブジェクトが存在することが保証されているので(はずなので)チェック省略 |
@@ -161,6 +182,7 @@ | ||
161 | 182 | if not event == 'get': return |
162 | 183 | try: self.rule |
163 | 184 | except: return # undefined rule error!! |
185 | + if TRACE: print '- get -> %s.%s' % (attr.owner().__class__.__name__,self.name) | |
164 | 186 | # |
165 | 187 | # Event からの循環参照を検出したら脱出する |
166 | 188 | # |
@@ -182,9 +204,13 @@ | ||
182 | 204 | owner = attr.owner() |
183 | 205 | for name in self.dependency: # 依存関係のある Terminal がひとつでも更新されていれば else 節を実行してなにもせず脱出 |
184 | 206 | myattr = terminal(owner,name).get_attribute(owner) |
185 | - if not attr in myattr.node.getlog: break | |
207 | + if TRACE: print '[%s]' % name, | |
208 | + if not attr in myattr.node.getlog: | |
209 | + if TRACE: print 'modified' | |
210 | + break | |
186 | 211 | else: # 依存関係のある Terminal がひとつも更新されていなかった場合(break で脱出しなかった場合) |
187 | - if not len(self.dependency) == 0: return # 依存関係が()の場合にも else 節が実行されてしまう例外処理 | |
212 | + if not len(self.dependency) == 0: | |
213 | + return # 依存関係が()の場合にも else 節が実行されてしまう例外処理 | |
188 | 214 | # |
189 | 215 | # ルールの実行に先立って依存ターミナルへ get を通知しリンクを遡り getlog を更新する |
190 | 216 | # |
@@ -194,7 +220,7 @@ | ||
194 | 220 | for o in dependent.node.get_observers(): |
195 | 221 | if isinstance(o.terminal(),Rule): |
196 | 222 | o.ignore[dependent] = None |
197 | - getattr(owner,name) | |
223 | + getattr(owner,name) # 依存ターミナルを参照してルール起動を試みる | |
198 | 224 | for o in dependent.node.get_observers(): |
199 | 225 | try: |
200 | 226 | o.detected |
@@ -213,16 +239,17 @@ | ||
213 | 239 | # |
214 | 240 | # ルールの実行 |
215 | 241 | # |
242 | + if TRACE: print 'exec %s.%s.rule' % (attr.owner().__class__.__name__,self.name) | |
216 | 243 | attr.node.value = self.rule(owner) # rule を実行してその結果を node に保存する |
217 | 244 | attr.node.getlog.clear() # node を変更したので node.getlog を消去 |
245 | + if TRACE: print '%s.%s - set ->' % (attr.owner().__class__.__name__,self.name) | |
218 | 246 | attr.node.notify('set',ignore=attr.ignore) |
219 | 247 | attr.ignore.clear() |
220 | - | |
248 | + | |
221 | 249 | class Event(Terminal): |
222 | 250 | def __init__(self,value=None,*args,**kw): |
223 | 251 | Terminal.__init__(self,value) |
224 | 252 | if 'rule' in kw: self.rule = kw['rule'] |
225 | - self.from_rule = None | |
226 | 253 | def notify(self, attr, event): |
227 | 254 | if not event == 'set': return |
228 | 255 | try: self.rule |
@@ -0,0 +1,56 @@ | ||
1 | +# coding: utf-8 | |
2 | +from pylafii import Terminal, rule, connect | |
3 | +from pylafii import Entry, Button | |
4 | +from pylafii import Logic, Equipment, Embed | |
5 | +from pylafii import MatrixPlotPanel | |
6 | +from pylafii import InteractiveWidget, Panel, Layout | |
7 | +from numpy import arange, zeros, pi, sin | |
8 | +from scipy import rand | |
9 | +import Tkinter | |
10 | +import weakref | |
11 | + | |
12 | +class AutoTrig(Logic): | |
13 | + value = Terminal() | |
14 | + class Control(Panel): | |
15 | + def layout(self): | |
16 | + InteractiveWidget(self,name='value').pack() | |
17 | + self.children['value'].switch = True | |
18 | + self.children['value'].interval = 10 | |
19 | + | |
20 | +class LogicA(Logic): | |
21 | + counter = 0 | |
22 | + freq = Terminal(0.01) | |
23 | + points = Terminal(500) | |
24 | + speed = Terminal(100) | |
25 | + @rule() | |
26 | + def result(self): | |
27 | + a = zeros((self.points,2)) | |
28 | + a[:,0] = arange(self.points) | |
29 | + a[:,1] = sin(2. * pi * self.freq * a[:,0] + 2. * pi * self.counter / self.speed) | |
30 | + self.counter = self.counter + 1 | |
31 | + if self.counter >= self.speed: self.counter = 0 | |
32 | +# a[:,1] = rand(self.points) | |
33 | + return a | |
34 | + class Control(Panel): | |
35 | + def layout(self): | |
36 | + Entry(self,name='freq').pack() | |
37 | + Entry(self,name='points').pack() | |
38 | + Entry(self,name='speed').pack() | |
39 | + Button(self,name='result',text='Trig').pack() | |
40 | + class Plot(MatrixPlotPanel): pass | |
41 | + | |
42 | +tk = Tkinter.Tk() | |
43 | + | |
44 | +o = Equipment(tk,LogicA).pack() | |
45 | +i = Embed(o.layout.rack,AutoTrig,Layout).pack() | |
46 | +connect((o.logic,'result'),(i.logic,'value')) | |
47 | + | |
48 | +#o.panel['plot'].children['result'].layout.popup_config() | |
49 | +#o.logic.nos = 8 | |
50 | +#o.panel['plot'].children['result'].logic.plot.ax.set_title('TITLE') | |
51 | + | |
52 | +# print '-------------' | |
53 | +tk.mainloop() | |
54 | + | |
55 | +i = weakref.ref(i); print i | |
56 | +o = weakref.ref(o); print o |
@@ -240,9 +240,9 @@ | ||
240 | 240 | self.assertEqual(a.status(),[True, True, True]) |
241 | 241 | self.assertEqual(b.status(),[True, True, True]) |
242 | 242 | b.a = 1 |
243 | - self.assertEqual(a.count,1); a.count = 0 # dependent が更新されているのでルールが1回実行される | |
243 | + self.assertEqual(a.count,0); # ルールは評価されない | |
244 | 244 | self.assertEqual(b.count,1); b.count = 0 # dependent が更新されているのでルールが1回実行される |
245 | - self.assertEqual(a.status(),[True, False, True]) | |
245 | + self.assertEqual(a.status(),[True, True, True]) | |
246 | 246 | self.assertEqual(b.status(),[True, False, True]) |
247 | 247 | # |
248 | 248 | # 循環接続した後に任意の dependent から get された場合 |