| Home | Trees | Indices | Help |
|
|---|
|
|
1 #-------------------------------------------------------------------------------
2 #
3 # Define the classes to handled 'synched' and 'unsynched' delegated traits.
4 #
5 # Written by: David C. Morrill
6 #
7 # Date: 06/21/2002
8 #
9 # Refactored into a separate module: 07/04/2003
10 #
11 # Symbols defined: TraitGetterSetter
12 # TraitDelegate
13 # TraitDelegateSynched
14 # TraitEvent
15 # TraitProperty
16 #
17 # (c) Copyright 2002, 2003 by Enthought, Inc.
18 #
19 #-------------------------------------------------------------------------------
20
21 #-------------------------------------------------------------------------------
22 # Imports:
23 #-------------------------------------------------------------------------------
24 from __future__ import division # confidence high
25
26 from __future__ import nested_scopes
27 from types import StringType, MethodType, InstanceType, ClassType, \
28 TypeType
29 from trait_base import Undefined, CoercableFuncs, class_of, trait_editors
30 from trait_errors import TraitError, DelegationError
31
32 #-------------------------------------------------------------------------------
33 # Constants:
34 #-------------------------------------------------------------------------------
35
36 EmptyDict = {}
37
38 HasTraits = None # Patched by 'traits.py' once class is defined!
39
40 #-------------------------------------------------------------------------------
41 # 'TraitGetterSetter' class (Abstract class):
42 #-------------------------------------------------------------------------------
43
48
49 #-------------------------------------------------------------------------------
50 # 'TraitDelegate' class:
51 #-------------------------------------------------------------------------------
52
54
55 __traits_metadata__ = {
56 'type': 'delegate'
57 }
58
60 self._delegate = delegate
61 self.delegate = self.get_delegate
62 self.getattr = self.getattr_method
63 self.setattr = self.setattr # Performance hack!
64 self.prefix = ''
65 self.mutate = False
66 if type( mutate_or_prefix ) is StringType:
67 self.prefix = mutate_or_prefix
68 self.name = self.replace_name
69 if mutate_or_prefix[-1:] == '*':
70 self.prefix = mutate_or_prefix[:-1]
71 self.name = self.prefix_name
72 if mutate_or_prefix == '*':
73 self.name = self.classprefix_name
74 else:
75 self.mutate = mutate_or_prefix
76
77 # Handle the special case of a delegate that disallows everything:
78 if delegate is None:
79 self.getattr = self.getattr_locked
80 self.setattr = self.setattr_locked
81
82 #----------------------------------------------------------------------------
83 # Return the delegate for a specified object:
84 #----------------------------------------------------------------------------
85
87 if hasattr( object, self._delegate ):
88 delegate = getattr( object, self._delegate )
89 if type( delegate ) is MethodType:
90 self.getattr = self.getattr_method
91 self.delegate = delegate
92 return delegate( object )
93 self.getattr = getattr( self, 'getattr_trait_' + self.name.__name__ )
94 self.delegate = self._getattr
95 return self._getattr( object )
96
97 #----------------------------------------------------------------------------
98 # Return a delegate stored as an object trait:
99 #----------------------------------------------------------------------------
100
102 return getattr( object, self._delegate )
103
104 #----------------------------------------------------------------------------
105 # Define variations on creating the trait name to delegate to:
106 #----------------------------------------------------------------------------
107
109 return name
110
113
115 return self.prefix + name
116
118 return object.__prefix__ + name
119
120 #----------------------------------------------------------------------------
121 # Return an object delegate's value for a specified trait:
122 # (for the case where the delegate is a trait)
123 #
124 # Note: There is one variant for each type of delegate 'name'. They are
125 # expanded out this way to eliminate a method call to 'self.name'
126 # and thus optimize the delegation 'getattr' code path.
127 #----------------------------------------------------------------------------
128
130 try:
131 return getattr( getattr( object, self._delegate ), name )
132 except:
133 return self.getattr_exception( object, name, value )
134
136 try:
137 return getattr( getattr( object, self._delegate ), self.prefix )
138 except:
139 return self.getattr_exception( object, name, value )
140
142 try:
143 return getattr( getattr( object, self._delegate ),
144 self.prefix + name )
145 except:
146 return self.getattr_exception( object, name, value )
147
149 try:
150 return getattr( getattr( object, self._delegate ),
151 object.__prefix__ + name )
152 except:
153 return self.getattr_exception( object, name, value )
154
155 #----------------------------------------------------------------------------
156 # Common exception handler for a trait delegate:
157 #----------------------------------------------------------------------------
158
160 if getattr( object, self._delegate ) is None:
161 if value is not Undefined:
162 return value
163 raise DelegationError, (
164 "Attempted to get the '%s' trait of %s instance, "
165 "but its '%s' delegate is not defined." % (
166 name, class_of( object ), self._delegate ) )
167 else:
168 raise DelegationError, (
169 "Attempted to get the '%s' trait of %s instance, "
170 "but its '%s' delegate does not have the trait defined."
171 % ( name, class_of( object ), self._delegate ) )
172
173 #----------------------------------------------------------------------------
174 # Return an object delegate's value for a specified trait:
175 # (for the case where the delegate is a method)
176 #----------------------------------------------------------------------------
177
179 delegate = self.delegate( object )
180 try:
181 return getattr( delegate, self.name( object, name ) )
182 except:
183 if delegate is None:
184 if value is not Undefined:
185 return value
186 raise DelegationError, (
187 "Attempted to get the '%s' trait of %s instance, "
188 "but its '%s' delegate is not defined." % (
189 name, class_of( object ), self._delegate ) )
190 else:
191 raise DelegationError, (
192 "Attempted to get the '%s' trait of %s instance, "
193 "but its '%s' delegate does not have the trait defined."
194 % ( name, class_of( object ), self._delegate ) )
195
196 #----------------------------------------------------------------------------
197 # Throw an exception when a 'locked' trait is referenced:
198 #----------------------------------------------------------------------------
199
201 raise AttributeError, "%s instance has no attribute '%s'" % (
202 object.__class__.__name__, name )
203
204 #----------------------------------------------------------------------------
205 # Validate the value for a particular object delegate's trait:
206 #----------------------------------------------------------------------------
207
209 try:
210 delegate_name = self.name( object, name )
211 delegate = self.delegate( object )
212 while True:
213 handler = delegate._trait( delegate_name ).setter
214 if not isinstance( handler, TraitDelegate ):
215 break
216 delegate = handler.delegate( delegate )
217 except AttributeError:
218 if delegate is None:
219 raise DelegationError, (
220 "Attempted to set the '%s' trait of %s instance, "
221 "but its '%s' delegate is not defined." % (
222 name, class_of( object ), self._delegate ) )
223 else:
224 raise DelegationError, (
225 "Attempted to set the '%s' trait of %s instance, but "
226 "its '%s' delegate does not have any traits defined." %
227 ( name, class_of( object ), self._delegate ) )
228 except:
229 raise DelegationError, (
230 "Attempted to set the '%s' trait of %s instance, but its "
231 "'%s' delegate does not have a trait with that name." % (
232 name, class_of( object ), self._delegate ) )
233
234 if self.mutate:
235 # Modify the delegate object:
236 try:
237 return handler.setattr( delegate, delegate_name, value, default )
238 except TraitError, excp:
239 # The exception is for the wrong object. Fix it, then pass it on:
240 excp.set_desc( delegate._trait( delegate_name ).desc, object )
241 raise excp
242 else:
243 # Modify the original object:
244 try:
245 return handler.setattr( object, name, value, default )
246 except TraitError, excp:
247 # Add the trait description to the exception:
248 excp.set_desc( delegate._trait( delegate_name ).desc )
249 raise excp
250
251 #----------------------------------------------------------------------------
252 # Throw an exception when a 'locked' trait is set:
253 #----------------------------------------------------------------------------
254
256 raise TraitError, "%s instance does not have a '%s' trait" % (
257 class_of( object ).capitalize(), name )
258
259 #----------------------------------------------------------------------------
260 # Get the base trait for a particular object delegate's trait:
261 #----------------------------------------------------------------------------
262
264 try:
265 delegate = self.delegate( object )
266 while True:
267 trait = delegate._trait( self.name( object, name ) )
268 handler = trait.setter
269 if not isinstance( handler, TraitDelegate ):
270 break
271 delegate = handler.delegate( delegate )
272 return trait
273 except AttributeError:
274 if delegate is None:
275 raise DelegationError, (
276 "Attempted to get the underlying '%s' trait of a "
277 "%s instance, but its '%s' delegate is not defined." % (
278 name, object.__class__.__name__, self._delegate ) )
279 else:
280 raise DelegationError, (
281 "Attempted to get the underlying '%s' trait of a "
282 "%s instance, but its '%s' delegate does not have any "
283 "traits defined." %
284 ( name, object.__class__.__name__, self._delegate ) )
285 except:
286 raise DelegationError, (
287 "Attempted to get the underlying '%s' trait of a "
288 "%s instance, but its '%s' delegate does not have a "
289 "trait with that name." % (
290 name, object.__class__.__name__, self._delegate ) )
291
292 #-------------------------------------------------------------------------------
293 # 'TraitDelegateSynched' class:
294 #-------------------------------------------------------------------------------
295
297
299 self.original_setattr = self.setattr
300 TraitDelegate.__init__( self, delegate, mutate_or_prefix )
301 if delegate is not None:
302 self.getattr = self.getattr_init
303 self.setattr = self.setattr_init
304
305 #----------------------------------------------------------------------------
306 # Decide which type of attribute getter to use the very first time this
307 # trait is used to get the trait's value:
308 #----------------------------------------------------------------------------
309
313
314 #----------------------------------------------------------------------------
315 # Validate the value for a particular object delegate's trait:
316 #----------------------------------------------------------------------------
317
321
322 #----------------------------------------------------------------------------
323 # Bind the getattr/settatr methods the first time delegation occurs:
324 #----------------------------------------------------------------------------
325
327 self.get_delegate( object )
328 self.setattr = self.original_setattr
329 if self.getattr != self.getattr_method:
330 self.getattr = self.getattr_synched
331 if not self.mutate:
332 self.setattr = self.setattr_synched
333
334 #----------------------------------------------------------------------------
335 # Return an object delegate's value for a specified trait:
336 # (for the case where the delegate is an attribute)
337 #----------------------------------------------------------------------------
338
340 delegate = self.delegate( object )
341 try:
342 delegate_name = self.name( object, name )
343 value = getattr( delegate, delegate_name )
344 if not isinstance( delegate, HasTraits ):
345 return value
346 setattr( object, name, value )
347 dict = object.__dict__
348 delegates = dict.get( '__delegates__', None )
349 if delegates is None:
350 dict[ '__delegates__' ] = delegates = {}
351 handlers = delegates.get( self._delegate, None )
352 if handlers is None:
353 delegates[ self._delegate ] = handlers = {}
354 object.on_trait_change( self.delegate_changed, self._delegate )
355 handler = lambda v: object._set_trait_value( object, name, v, None )
356 handlers[ name ] = ( handler, delegate_name )
357 delegate.on_trait_change( handler, delegate_name )
358 return value
359 except:
360 return self.getattr_exception( object, name, value )
361
362 #----------------------------------------------------------------------------
363 # Handle one of an object's delegates being assigned a new value:
364 #----------------------------------------------------------------------------
365
367 handlers = object.__delegates__[ trait_name ]
368 for name, info in handlers.items():
369 handler, delegate_name = info
370 old.on_trait_change( handler, delegate_name, True )
371 new.on_trait_change( handler, delegate_name )
372 object._set_trait_value( object, name,
373 getattr( new, delegate_name ), None )
374
375 #----------------------------------------------------------------------------
376 # Validate the value for a particular object delegate's trait:
377 #----------------------------------------------------------------------------
378
380 TraitDelegate.setattr( self, object, name, value, default )
381 handlers = object.__dict__.get( '__delegates__', EmptyDict ).get(
382 self._delegate, EmptyDict )
383 info = handlers.get( name, None )
384 if info is not None:
385 handler, delegate_name = info
386 self.delegate( object ).on_trait_change( handler, delegate_name,
387 True )
388 del handlers[ name ]
389
390 #-------------------------------------------------------------------------------
391 # 'TraitEvent' class:
392 #-------------------------------------------------------------------------------
393
395
396 __traits_metadata__ = {
397 'type': 'event'
398 }
399
400 #----------------------------------------------------------------------------
401 # Initialize the object:
402 #----------------------------------------------------------------------------
403
405 if klass is None:
406 self.validate = self.any_value_validate
407 else:
408 self.kind = klass
409 kind = type( klass )
410 if kind is not ClassType:
411 self.validate = self.type_validate
412 if kind is not TypeType:
413 self.kind = kind
414 try:
415 self.coerce = CoercableFuncs[ kind ]
416 except:
417 self.coerce = self.identity
418
420 if isinstance( value, self.kind ):
421 return value
422 raise TraitError, ( object, name,
423 '%s instance' % class_of( self.kind.__name__ ), value )
424
427
429 try:
430 return self.coerce( value )
431 except:
432 pass
433 if type( value ) is InstanceType:
434 kind = class_of( value )
435 else:
436 kind = repr( value )
437 raise TraitError, ( object, name, 'of %s' % str( self.kind )[1:-1],
438 '%s (i.e. %s)' % ( str( type( value ) )[1:-1], kind ) )
439
444
446 return object._set_event_value( object, name,
447 self.validate( object, name, value ), default )
448
452
453 #-------------------------------------------------------------------------------
454 # 'TraitProperty' class:
455 #-------------------------------------------------------------------------------
456
458
459 __traits_metadata__ = {
460 'type': 'property'
461 }
462
463 #----------------------------------------------------------------------------
464 # Initialize the object:
465 #----------------------------------------------------------------------------
466
468 if fget is not None:
469 self.getattr = PropertyGetWrapper( fget )
470
471 if fset is not None:
472 self.setattr = PropertySetWrapper( fset )
473 self.get_editor = self._get_editor
474
476 raise AttributeError, "the %s trait of %s instance is read only" % (
477 name, class_of( object ) )
478
480 raise AttributeError, "the %s trait of %s instance is write only" % (
481 name, class_of( object ) )
482
486
487 #-------------------------------------------------------------------------------
488 # 'PropertySetWrapper' class:
489 #-------------------------------------------------------------------------------
490
492
494 self.handler = handler
495 self.__call__ = getattr( self, 'call_%d' %
496 handler.func_code.co_argcount )
497
500
503
506
509
510 #-------------------------------------------------------------------------------
511 # 'PropertyGetWrapper' class:
512 #-------------------------------------------------------------------------------
513
529
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Aug 22 14:36:04 2011 | http://epydoc.sourceforge.net |