Package pydrizzle :: Package traits102 :: Module trait_delegates
[hide private]
[frames] | no frames]

Source Code for Module pydrizzle.traits102.trait_delegates

  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   
44 -class TraitGetterSetter:
45
46 - def metadata ( self ):
47 return getattr( self, '__traits_metadata__', {} )
48 49 #------------------------------------------------------------------------------- 50 # 'TraitDelegate' class: 51 #------------------------------------------------------------------------------- 52
53 -class TraitDelegate (TraitGetterSetter ):
54 55 __traits_metadata__ = { 56 'type': 'delegate' 57 } 58
59 - def __init__ ( self, delegate = None, mutate_or_prefix = False ):
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
86 - def get_delegate ( self, object ):
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
101 - def _getattr ( self, object ):
102 return getattr( object, self._delegate )
103 104 #---------------------------------------------------------------------------- 105 # Define variations on creating the trait name to delegate to: 106 #---------------------------------------------------------------------------- 107
108 - def name ( self, object, name ):
109 return name
110
111 - def replace_name ( self, object, name ):
112 return self.prefix
113
114 - def prefix_name ( self, object, name ):
115 return self.prefix + name
116
117 - def classprefix_name ( self, object, name ):
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
129 - def getattr_trait_name ( self, object, name, value ):
130 try: 131 return getattr( getattr( object, self._delegate ), name ) 132 except: 133 return self.getattr_exception( object, name, value )
134
135 - def getattr_trait_replace_name ( self, object, name, value ):
136 try: 137 return getattr( getattr( object, self._delegate ), self.prefix ) 138 except: 139 return self.getattr_exception( object, name, value )
140
141 - def getattr_trait_prefix_name ( self, object, name, value ):
142 try: 143 return getattr( getattr( object, self._delegate ), 144 self.prefix + name ) 145 except: 146 return self.getattr_exception( object, name, value )
147
148 - def getattr_trait_classprefix_name ( self, object, name, value ):
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
159 - def getattr_exception ( self, object, name, value ):
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
178 - def getattr_method ( self, object, name, value ):
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
200 - def getattr_locked ( self, object, name, value ):
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
208 - def setattr ( self, object, name, value, default ):
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
255 - def setattr_locked ( self, object, name, value, default ):
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
263 - def base_trait ( self, object, name ):
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
296 -class TraitDelegateSynched ( TraitDelegate ):
297
298 - def __init__ ( self, delegate = None, mutate_or_prefix = False ):
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
310 - def getattr_init ( self, object, name, value ):
311 self.delegate_init( object ) 312 return self.getattr( object, name, value )
313 314 #---------------------------------------------------------------------------- 315 # Validate the value for a particular object delegate's trait: 316 #---------------------------------------------------------------------------- 317
318 - def setattr_init ( self, object, name, value, default ):
319 self.delegate_init( object ) 320 self.setattr( object, name, value, default )
321 322 #---------------------------------------------------------------------------- 323 # Bind the getattr/settatr methods the first time delegation occurs: 324 #---------------------------------------------------------------------------- 325
326 - def delegate_init ( self, object ):
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
339 - def getattr_synched ( self, object, name, value ):
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
366 - def delegate_changed ( self, object, trait_name, old, new ):
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
379 - def setattr_synched ( self, object, name, value, default ):
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
394 -class TraitEvent ( TraitGetterSetter ):
395 396 __traits_metadata__ = { 397 'type': 'event' 398 } 399 400 #---------------------------------------------------------------------------- 401 # Initialize the object: 402 #---------------------------------------------------------------------------- 403
404 - def __init__ ( self, klass = None ):
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
419 - def validate ( self, object, name, value ):
420 if isinstance( value, self.kind ): 421 return value 422 raise TraitError, ( object, name, 423 '%s instance' % class_of( self.kind.__name__ ), value )
424
425 - def any_value_validate ( self, object, name, value ):
426 return value
427
428 - def type_validate ( self, object, name, value ):
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
440 - def identity ( self, value ):
441 if type( value ) is self.kind: 442 return value 443 raise TraitError
444
445 - def setattr ( self, object, name, value, default ):
446 return object._set_event_value( object, name, 447 self.validate( object, name, value ), default )
448
449 - def getattr ( self, object, name, value ):
450 raise AttributeError, ( "the %s trait of %s instance is an 'event', " 451 "which is write only" % ( name, class_of( object ) ) )
452 453 #------------------------------------------------------------------------------- 454 # 'TraitProperty' class: 455 #------------------------------------------------------------------------------- 456
457 -class TraitProperty ( TraitGetterSetter ):
458 459 __traits_metadata__ = { 460 'type': 'property' 461 } 462 463 #---------------------------------------------------------------------------- 464 # Initialize the object: 465 #---------------------------------------------------------------------------- 466
467 - def __init__ ( self, fget = None, fset = None ):
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
475 - def setattr ( self, object, name, value, default ):
476 raise AttributeError, "the %s trait of %s instance is read only" % ( 477 name, class_of( object ) )
478
479 - def getattr ( self, object, name, value ):
480 raise AttributeError, "the %s trait of %s instance is write only" % ( 481 name, class_of( object ) )
482
483 - def _get_editor ( self, trait ):
484 return trait_editors().TraitEditorText( evaluate = True, 485 auto_set = False )
486 487 #------------------------------------------------------------------------------- 488 # 'PropertySetWrapper' class: 489 #------------------------------------------------------------------------------- 490
491 -class PropertySetWrapper:
492
493 - def __init__ ( self, handler ):
494 self.handler = handler 495 self.__call__ = getattr( self, 'call_%d' % 496 handler.func_code.co_argcount )
497
498 - def call_0 ( self, object, trait_name, value, default ):
499 return self.handler()
500
501 - def call_1 ( self, object, trait_name, value, default ):
502 return self.handler( object )
503
504 - def call_2 ( self, object, trait_name, value, default ):
505 return self.handler( object, value )
506
507 - def call_3 ( self, object, trait_name, value, default ):
508 return self.handler( object, trait_name, value )
509 510 #------------------------------------------------------------------------------- 511 # 'PropertyGetWrapper' class: 512 #------------------------------------------------------------------------------- 513
514 -class PropertyGetWrapper:
515
516 - def __init__ ( self, handler ):
517 self.handler = handler 518 self.__call__ = getattr( self, 'call_%d' % 519 handler.func_code.co_argcount )
520
521 - def call_0 ( self, object, trait_name, default ):
522 return self.handler()
523
524 - def call_1 ( self, object, trait_name, default ):
525 return self.handler( object )
526
527 - def call_2 ( self, object, trait_name, default ):
528 return self.handler( object, trait_name )
529