[Subversion] / PEAK / src / peak / binding / components.py  

Diff of /PEAK/src/peak/binding/components.py

Parent Directory | Revision Log

version 469, Sat Jul 13 21:02:40 2002 UTC version 1140, Mon May 26 17:22:23 2003 UTC
Line 1 
Line 1 
 """Basic binding tools"""  """Basic binding tools"""
   
 from once import Once, New, WeakBinding  from __future__ import generators
 import meta, modules  from peak.api import *
   
 from weakref import ref, WeakValueDictionary  from once import *
   from interfaces import *
 from peak.naming.names import toName, Syntax, CompoundName  from types import ModuleType
 from peak.naming.interfaces import NameNotFoundException  from peak.naming.names import toName, AbstractName, COMPOUND_KIND, IName
 from peak.util.EigenData import EigenRegistry  from peak.naming.syntax import PathSyntax
   from peak.util.EigenData import AlreadyRead, EigenRegistry
 from Interface import Interface  from peak.config.interfaces import IConfigKey, IPropertyMap, \
 from peak.api import config, NOT_FOUND      IConfigurationRoot, NullConfigRoot
   from peak.util.imports import importString
   from warnings import warn
   
   class ComponentSetupWarning(UserWarning):
       """Large iterator passed to suggestParentComponent"""
   
 __all__ = [  __all__ = [
     'Component','AutoCreated','Provider','CachingProvider',      'Base', 'Component', 'ComponentSetupWarning', 'whenAssembled',
     'bindTo', 'requireBinding', 'bindToNames', 'bindToParent', 'bindToSelf',      'bindTo', 'requireBinding', 'bindSequence', 'bindToParent', 'bindToSelf',
     'getRootComponent', 'getParentComponent', 'lookupComponent',      'getRootComponent', 'getParentComponent', 'lookupComponent',
     'acquireComponent', 'globalLookup'      'acquireComponent', 'suggestParentComponent', 'notifyUponAssembly',
       'bindToUtilities', 'bindToProperty', 'Constant', 'delegateTo',
       'getComponentName', 'getComponentPath', 'Acquire', 'ComponentName',
 ]  ]
   
   
 InterfaceClass = Interface.__class__  class _proxy(Once):
   
   
   
       def __init__(self,attrName):
           self.attrName = attrName
   
       def usageError(self):
           raise AttributeError, self.attrName
   
       def computeValue(self,d,a): raise AttributeError, a
   
   
   
   def getComponentPath(component, relativeTo=None):
   
       """Get 'ComponentName' that would traverse from 'relativeTo' to 'component'
   
       If 'relativeTo' is 'None' or not supplied, the path returned is relative
       to the root component of 'component'.  Note that if supplied, 'relativeTo'
       must be an ancestor (parent, parent's parent, etc.) of 'component'."""
   
       path = []; root=None
   
       if relativeTo is None:
           root = getRootComponent(component)
   
       c = component
   
       while 1:
   
           if c is root:
               path.append(''); break
   
           elif c is relativeTo:
               break
   
 def Provider(callable):          path.append(getComponentName(c) or '*')
     return lambda foundIn, forObj: callable(forObj)  
   
           c = getParentComponent(c)
   
 def CachingProvider(callable, weak=False):          if c is None:
               break
   
     def provider(foundIn, forObj):      path.reverse()
       return ComponentName(path)
   
         fid = id(foundIn)  
         utility = provider.cache.get(fid)  
   
         if utility is None:  
             utility = provider.cache[fid] = callable(foundIn)  
   
         return utility  
   
     if weak:  
         provider.cache = WeakValueDictionary()  
     else:  
         provider.cache = {}  
   
     return provider  
   
   
   
   
   def Constant(provides, value, doc=None):
       """Supply a constant as a property or utility"""
       return Once(lambda s,d,a: value, provides=provides, doc=doc)
   
   
   def getParentComponent(component):
   
       """Return parent of 'component', or 'None' if root or non-component"""
   
       try:
           gpc = component.getParentComponent
   
       except AttributeError:
   
           if isinstance(component,ModuleType):
               m = '.'.join(component.__name__.split('.')[:-1])
               if m: return importString(m)
   
       else:
           return gpc()
   
   
   def getComponentName(component):
   
       """Return name of 'component', or 'None' if root or non-component"""
   
       try:
           gcn = component.getComponentName
   
       except AttributeError:
   
           if isinstance(component,ModuleType):
               return component.__name__.split('.')[-1]
   
       else:
           return gcn()
   
 def getParentComponent(component):  
   
     """Return parent of 'component', or 'None' if root or non-component"""  
   
     try:  
         gpc = component.getParentComponent  
     except AttributeError:  
         pass  
     else:  
         return gpc()  
   
   
 def getRootComponent(component):  def getRootComponent(component):
Line 105 
Line 134 
     return component      return component
   
   
 def globalLookup(name, component=None):  
   
     """Lookup 'name' in global 'InitialContext', w/'component' in environ"""  
   
     from peak.naming.api import InitialContext  def notifyUponAssembly(parent,child):
   
       """Call 'child.uponAssembly()' as soon as 'parent' knows all its parents"""
   
       try:
           nua = parent.notifyUponAssembly
   
       except AttributeError:
   
           parent = getParentComponent(parent)
   
           if parent is None:
               child.uponAssembly()
           else:
               notifyUponAssembly(parent,child)
   
     return InitialContext(RELATIVE_TO_COMPONENT=component).lookup(name)      else:
           nua(child)
   
   
   
Line 120 
Line 162 
   
   
   
   def acquireComponent(component, name, creationName=None):
   
 def acquireComponent(component, name):      """Acquire 'name' relative to 'component', w/fallback to naming.lookup()
   
     """Acquire 'name' relative to 'component', w/fallback to globalLookup()"""      'name' is looked for as an attribute of 'component'.  If not found,
       the component's parent will be searched, and so on until the root component
       is reached.  If 'name' is still not found, and the root component
       implements 'config.IConfigurationRoot', the name will be looked up in the
       default naming context, if any.  Otherwise, a NameNotFound error will be
       raised."""
   
     target = component      prev = target = component
   
     while target is not None:      while target is not None:
   
Line 134 
Line 182 
         if ob is not NOT_FOUND:          if ob is not NOT_FOUND:
             return ob              return ob
   
           prev = target
         target = getParentComponent(target)          target = getParentComponent(target)
   
     else:      else:
         return globalLookup(name, component)          return adapt(
               prev, IConfigurationRoot, NullConfigRoot
           ).nameNotFound(
               prev, name, component, creationName
           )
   
   
   
   
   
   
   
Line 146 
Line 203 
   
   
   
   class ComponentName(AbstractName):
   
       """Path between components
   
       Component Path Syntax
   
           Paths are '"/"' separated attribute names.  Path segments of '"."' and
           '".."' mean the same as they do in URLs.  A leading '"/"' (or a
           compound name beginning with an empty path segment), will be treated
           as an "absolute path" relative to the component's root component.
   
           Paths beginning with anything other than '"/"', '"./"', or '"../"' are
           acquired, which means that the first path segment will be looked
           up using 'acquireComponent()' before processing the rest of the path.
           (See 'acquireComponent()' for more details.)  If you do not want
           a name to be acquired, simply prefix it with './' so it is relative
           to the starting object.
   
           All path segments after the first are interpreted as attribute names
           to be looked up, beginning at the component referenced by the first
           path segment.  '.' and '..' are interpreted the same as for the first
           path segment.
       """
   
       nameKind = COMPOUND_KIND
   
       syntax = PathSyntax(
           direction = 1,
           separator = '/',
       )
   
       protocols.advise(
           instancesProvide=[IComponentKey]
       )
   
   
   
Line 159 
Line 244 
   
   
   
       def lookup(self, component, default=NOT_GIVEN, creationName=None):
   
           if not self:  # empty name refers to self
               return component
   
           parts = iter(self)
           attr = parts.next()                 # first part
           pc = _getFirstPathComponent(attr)
   
 ComponentNameSyntax = Syntax(  
     direction = 1,          if pc:  ob = pc(component)
     separator = '/',          else:   ob = acquireComponent(component, attr, creationName)
   
           resolved = []
           append = resolved.append
   
           try:
               for attr in parts:
                   pc = _getNextPathComponent(attr)
                   if pc:  ob = pc(ob)
                   else:   ob = getattr(ob,attr)
                   append(attr)
   
           except AttributeError:
   
               if default is not NOT_GIVEN:
                   return default
   
               raise exceptions.NameNotFound(
                   resolvedName = ComponentName(resolved),
                   remainingName = ComponentName([attr] + [a for a in parts]),
                   resolvedObj = ob
 )  )
   
           return ob
   
   
   
   
 def ComponentName(nameStr):  
     return CompoundName(nameStr, ComponentNameSyntax)  
   
   
 _getFirstPathComponent = dict( (  _getFirstPathComponent = dict( (
Line 187 
Line 300 
   
   
   
   def lookupComponent(component, name, default=NOT_GIVEN, creationName=None):
   
       """Lookup 'name' relative to 'component'
   
       'name' can be any name acceptable to the 'peak.naming' package, or an
       Interface object.  Strings and compound names will be interpreted
       as paths relative to the starting component.  (See the 'ComponentName'
       class for details of path interpretation.)  An empty name will return
       the starting component.  Interfaces and Properties will be looked up using
       'config.findUtility(component, name)'.  All other kinds of names,
       including URL strings and 'CompositeName' instances, will be looked up
       using 'naming.lookup()'.
   
       Regardless of how the lookup is processed, an 'exceptions.NameNotFound'
       error will be raised if the name cannot be found."""
   
       return adapt(name, IComponentKey).lookup(component, default, creationName)
   
   
   
Line 200 
Line 326 
   
   
   
   class ConfigFinder(object):
   
       """Look up utilities or properties"""
   
       __slots__ = 'ob'
   
 def lookupComponent(component, name):      protocols.advise(
           instancesProvide = [IComponentKey],
           asAdapterForProtocols = [IConfigKey]
       )
   
     """Lookup 'name' relative to 'component'      def __init__(self, ob, proto):
           self.ob = ob
   
     'name' can be any name acceptable to the 'peak.naming' package, or an      def lookup(self, component, default, creationName=None):
     Interface object.  Strings and 'CompoundName' names will be interpreted          return config.findUtility(component, self.ob, default)
     as paths relative to the starting component.  An empty name will return  
     the starting component.  Interfaces will be lookedup using  
     'component.acquireUtility()'.  All other kinds of names, including URL  
     strings and 'CompositeName' instances, will be looked up using  
     'binding.globalLookup()'.  
   
     Regardless of how the lookup is processed, a 'naming.NameNotFoundException'  
     will be raised if the name cannot be found.  
   
     Component Path Syntax  
   
         Paths are '/'-separated attribute names.  Path segments of '.' and  
         '..' mean the same as they do in URLs.  A leading '/' (or a  
         CompoundName beginning with an empty path segment), will be treated  
         as an "absolute path" relative to the component's root component.  
   
         Paths beginning with anything other than '/', './', or '../' are  
         acquired, which means that the first path segment will be looked  
         up using 'acquireComponent()' before processing the rest of the path.  
         (See 'acquireComponent()' for more details.)  If you do not want  
         a name to be acquired, simply prefix it with './' so it is relative  
         to the starting object.  
   
         All path segments after the first are interpreted as attribute names  
         to be looked up, beginning at the component referenced by the first  
         path segment.  '.' and '..' are interpreted the same as for the first  
         path segment."""  
   
     if isinstance(name, InterfaceClass):  
         utility = component.acquireUtility(name)  
         if utility is None:  
             raise NameNotFoundException(name, resolvedObj = component)  
   
     parsedName = toName(name, ComponentName, 1)  
   
     # URL's and composite names must be handled globally  
   
     if not parsedName.isCompound:  
         return globalLookup(name, component)  
   
     if not parsedName:  
         # empty name refers to self  
         return component  
   
     parts = iter(parsedName)  
   
     attr = parts.next() # first part  
     pc = _getFirstPathComponent(attr)  
   
     if pc:  
         ob = pc(component)  
     else:  
         ob = acquireComponent(component,attr)  
   
     resolved = []  
     append = resolved.append  
   
     try:  
         for attr in parts:  
             pc = _getNextPathComponent(attr)  
             if pc:  
                 ob = pc(ob)  
             else:  
                 ob = getattr(ob,attr)  
             append(attr)  
   
     except AttributeError:  
   
         raise NameNotFoundException(  
             resolvedName = ComponentName(resolved),  
             remainingName = ComponentName([attr] + [a for a in parts]),  
             resolvedObj = ob  
         )  
   
     return ob  
   
 class bindTo(Once):  
   
     """Automatically look up and cache a relevant component  
   
         Usage::  
   
             class someClass(binding.Component):  
   
                 thingINeed = binding.bindTo("path/to/service")  
   
                 getOtherThing = binding.bindTo("some/thing", weak=True)  
   
         'someClass' can then refer to 'self.thingINeed' instead of  class NameFinder(object):
         calling 'self.lookupComponent("path/to/service")' repeatedly.  
         It can also do 'self.getOtherThing()' to get '"some/thing"'.  
         (The 'weak' argument, if true, means to bind to a weak reference.)  
     """  
   
     singleValue = True      """Look up names"""
   
     def __init__(self,targetName,weak=False,provides=None):      __slots__ = 'name'
   
         self.targetNames = (targetName,)      protocols.advise(
         self.weak = weak          instancesProvide      = [IComponentKey],
         self._provides=provides          asAdapterForTypes     = [str, unicode],
           asAdapterForProtocols = [IName]
       )
   
       def __init__(self, ob, proto):
           self.name = ob
   
       def lookup(self, component, default=NOT_GIVEN, creationName=None):
           parsedName = toName(self.name, ComponentName, 1)
   
           if not parsedName.nameKind == COMPOUND_KIND:
               # URL's and composite names must be handled globally
               try:
                   return naming.lookup(component, self.name,
                       creationParent=component, creationName=creationName
                   )
               except exceptions.NameNotFound:
                   if default is NOT_GIVEN:
                       raise
                   return default
   
           return ComponentName(parsedName).lookup(component,default,creationName)
   
   
   
Line 325 
Line 408 
   
   
   
   class bindTo(Once):
   
     def computeValue(self, obj, instanceDict, attrName):      """Automatically look up and cache a relevant component
   
           Usage::
   
               class someClass(binding.Component):
   
                   thingINeed = binding.bindTo("path/to/service")
   
           'someClass' can then refer to 'self.thingINeed' instead of
           calling 'self.lookupComponent("path/to/service")' repeatedly.
       """
       defaultValue = NOT_GIVEN
       singleValue = True
   
       def __init__(self,targetName,provides=None,doc=None,default=NOT_GIVEN,
           activateUponAssembly=False):
           self.defaultValue = default
           self.targetNames = (targetName,)
           self.declareAsProviderOf = provides
           self.__doc__ = doc or ("binding.bindTo(%r)" % targetName)
           self.activateUponAssembly = activateUponAssembly
   
       def computeValue(self, obj, instanceDict, attrName):
           default = self.defaultValue
         names = self.targetNames          names = self.targetNames
         obs   = map(obj.lookupComponent, names)          obs     = [lookupComponent(obj,n,default,attrName) for n in names]
   
         for name,newOb in zip(names, obs):          for name,newOb in zip(names, obs):
   
             if newOb is NOT_FOUND:              if newOb is NOT_FOUND:
   
                 del instanceDict[attrName]                  del instanceDict[attrName]
                 raise NameNotFoundError(attrName, resolvedName = name)                  raise exceptions.NameNotFound(attrName, resolvedName = name)
   
             if self.singleValue:              if self.singleValue:
   
                 if self.weak:  
                     return ref(newOb)  
                 else:  
                     return newOb                      return newOb
   
         if self.weak:  
             obs = map(ref,obs)  
   
         return tuple(obs)          return tuple(obs)
   
   class bindSequence(bindTo):
   
       """Automatically look up and cache a sequence of services by name
   
           Usage::
   
               class someClass(binding.AutoCreated):
   
                   thingINeed = binding.bindSequence(
                       "path/to/service", "another/path", ...
                   )
   
           'someClass' can then refer to 'self.thingINeed' to get a tuple of
           services instead of calling 'self.lookupComponent()' on a series of
           names.
       """
   
       singleValue = False
   
       def __init__(self, *targetNames, **kw):
           self.targetNames = targetNames
           self.declareAsProviderOf = kw.get('provides')
           self.__doc__ = kw.get('doc',("binding.bindSequence%s" % `targetNames`))
           self.activateUponAssembly = kw.get('activateUponAssembly')
   
   
   def whenAssembled(func, name=None, provides=None, doc=None):
       """'Once' function with 'activateUponAssembly' flag set"""
       return Once(
           func, name=name, provides=provides, doc=doc, activateUponAssembly=True
       )
   
   
   
Line 367 
Line 488 
   
   
   
 class bindToNames(bindTo):  
   
     """Automatically look up and cache a sequence of services by name  
   
         Usage::  def suggestParentComponent(parent,name,child):
   
             class someClass(binding.AutoCreated):      """Suggest to 'child' that it has 'parent' and 'name'
   
                 thingINeed = binding.bindToNames(      If 'child' does not support 'IComponent' and is a container that derives
                     "path/to/service", "another/path", ...      from 'tuple' or 'list', all of its elements that support 'IComponent'
                 )      will be given a suggestion to use 'parent' and 'name' as well.  Note that
       this means it would not be a good idea to use this on, say, a 10,000
       element list (especially if the objects in it aren't components), because
       this function has to check all of them."""
   
         'someClass' can then refer to 'self.thingINeed' to get a tuple of      ob = adapt(child,IComponent,None)
         services instead of calling 'self.lookupComponent()' on a series of  
         names.  As with 'bindTo()', a 'weak' keyword argument can be set to  
         indicate that the sequence should consist of weak references to the  
         named objects.  
     """  
   
     singleValue = False      if ob is not None:
           # Tell it directly
           ob.setParentComponent(parent,name,suggest=True)
   
     def __init__(self, *targetNames, **kw):      elif isinstance(child,(list,tuple)):
         self.targetNames = targetNames  
         self.weak = kw.get('weak')          ct = 0
         self._provides = kw.get('provides')  
   
           for ob in child:
   
               ob = adapt(ob,IComponent,None)
   
               if ob is not None:
                   ob.setParentComponent(parent,name,suggest=True)
               else:
                   ct += 1
                   if ct==100:
                       warn(
                           ("Large iterator for %s; if it will never"
                            " contain components, this is wasteful" % name),
                           ComponentSetupWarning, 3
                       )
   
   
   
   
   
   
   def delegateTo(delegateAttr, name=None, provides=None, doc=None):
   
       """Delegate attribute to the same attribute of another object
   
       Usage::
   
           class PasswordFile(binding.Component):
               shadow = binding.bindTo('config:etc.shadow/')
               checkPwd = changePwd = binding.delegateTo('shadow')
   
       The above is equivalent to this longer version::
   
           class PasswordFile(binding.Component):
               shadow = binding.bindTo('config:etc.shadow/')
               checkPwd = binding.bindTo('shadow/checkPwd')
               changePwd = binding.bindTo('shadow/changePwd')
   
       Because 'delegateTo' uses the attribute name being looked up, you do not
       need to create a separate binding for each attribute that is delegated,
       as you do when using 'bindTo()'."""
   
       return Once(
           lambda s,d,a: getattr(getattr(s,delegateAttr),a), name, provides, doc
       )
   
   def Acquire(key, doc=None, default=NOT_GIVEN, activateUponAssembly=False):
       """Provide a utility or property, but look it up if not supplied
   
       'key' must be a configuration key (e.g. an Interface or a PropertyName).
       If the attribute defined by this binding is not set, it will be looked up
       by finding the appropriate utility or property.  The attribute will also
       be registered as a source of that utility or property for child components.
       This allows you to easily override the configuration of the utility or
       property within a particular component subtree, simply by setting the
       attribute (e.g. via a constructor keyword)."""
   
       key = adapt(key,IConfigKey)
       return bindTo(key,key,doc,default,activateUponAssembly=activateUponAssembly)
   
   
   
 class bindToParent(WeakBinding):  def bindToParent(level=1, name=None, provides=None, doc=None):
   
     """Look up and cache a weak ref to the nth-level parent component      """Look up and cache a reference to the nth-level parent component
   
         Usage::          Usage::
   
Line 422 
Line 586 
        'self.getParentComponent().getParentComponent()'.         'self.getParentComponent().getParentComponent()'.
     """      """
   
     def __init__(self,level=1,provides=None):      def computeValue(obj, instDict, attrName):
         self.level = level  
         self._provides = provides  
   
     def computeValue(self, obj, instDict, attrName):          for step in range(level):
               newObj = getParentComponent(obj)
         for step in range(self.level):  
             newObj = obj.getParentComponent()  
             if newObj is None: break              if newObj is None: break
             obj = newObj              obj = newObj
   
         return obj          return obj
   
       return Once(computeValue, name=name, provides=provides, doc=doc)
   
   
 def bindToSelf(provides=None):  def bindToSelf(name=None, provides=None, doc=None):
   
     """Weak reference to the 'self' object      """Cached reference to the 'self' object
   
     This is just a shortcut for 'bindToParent(0)', and does pretty much what      This is just a shortcut for 'bindToParent(0)', and does pretty much what
     you'd expect.  It's handy for objects that provide default support for      you'd expect.  It's handy for objects that provide default support for
Line 446 
Line 608 
     can refer to 'self.delegateForInterfaceX.someMethod()', and have      can refer to 'self.delegateForInterfaceX.someMethod()', and have
     'delegateForInterfaceX' be a 'bindToSelf()' by default."""      'delegateForInterfaceX' be a 'bindToSelf()' by default."""
   
     return bindToParent(0,provides)      return bindToParent(0,name,provides,doc)
   
   
   
   
 class requireBinding(Once):  class requireBinding(Once):
   
     """Placeholder for a binding that should be (re)defined by a subclass"""      """Placeholder for a binding that should be (re)defined by a subclass"""
   
     def __init__(self,description="",provides=None):      def __init__(self,description="",name=None,provides=None,doc=None):
         self.description = description          self.description = description
         self._provides = provides          self.declareAsProviderOf = provides
           self.__doc__ = doc or ("binding.requireBinding: %s" % description)
           self.attrName = self.__name__ = name
   
     def computeValue(self, obj, instanceDict, attrName):      def computeValue(self, obj, instanceDict, attrName):
   
Line 464 
Line 630 
         )          )
   
   
   def bindToUtilities(iface,provides=None,doc=None,activateUponAssembly=False):
   
       """Binding to a list of all 'iface' utilities above the component"""
   
       return Once(lambda s,d,a: list(config.findUtilities(s,iface)),
           provides=provides, doc=doc, activateUponAssembly=activateUponAssembly
       )
   
   
   def bindToProperty(propName, default=NOT_GIVEN, provides=None, doc=None,
       activateUponAssembly=False):
   
       """Binding to property 'propName', defaulting to 'default' if not found
   
           If 'default' is not supplied, failure to locate the named property
           will result in a 'config.PropertyNotFound' exception.
       """
   
       propName = PropertyName(propName)
   
       return Once(lambda s,d,a: config.getProperty(s,propName,default),
           provides=provides, doc=doc, activateUponAssembly = activateUponAssembly
       )
   
   class _Base(object):
   
       """Basic attribute management and "active class" support"""
   
       __metaclass__ = ActiveClass
   
       protocols.advise(
           instancesProvide = [IBindableAttrs]
       )
   
       def _setBinding(self, attr, value, useSlot=False):
   
           self._bindingChanging(attr,value,useSlot)
   
           if useSlot:
               getattr(self.__class__,attr).__set__(self,value)
   
           else:
               self.__dict__[attr] = value
   
   
       def _getBinding(self, attr, default=None, useSlot=False):
   
           if useSlot:
               val = getattr(self,attr,default)
   
           else:
               val = self.__dict__.get(attr,default)
   
           if val is not default:
   
               val = self._postGet(attr,val,useSlot)
   
               if val is NOT_FOUND:
                   return default
   
           return val
   
   
   
   
       def _getBindingFuncs(klass, attr, useSlot=False):
           if useSlot:
               d = getattr(klass,attr)
           else:
               d = _proxy(attr)
           return d.__get__, d.__set__, d.__delete__
   
       _getBindingFuncs = classmethod(_getBindingFuncs)
   
   
       def _delBinding(self, attr, useSlot=False):
   
           self._bindingChanging(attr, NOT_FOUND, useSlot)
   
           if useSlot:
               d = getattr(self.__class__,attr).__delete__
   
               try:
                   d(self)
               except AttributeError:
                   pass
   
           elif attr in self.__dict__:
               del self.__dict__[attr]
   
       def _hasBinding(self,attr,useSlot=False):
   
           if useSlot:
               return hasattr(self,attr)
           else:
               return attr in self.__dict__
   
   
       def _bindingChanging(self,attr,newval,isSlot=False):
           pass
   
 class Component(object):  
       def _postGet(self,attr,value,isSlot=False):
           return value
   
   
   class Component(_Base):
   
     """Thing that can be composed into a component tree, w/binding & lookups"""      """Thing that can be composed into a component tree, w/binding & lookups"""
   
     __metaclasses__  = (      protocols.advise(
         meta.AssertInterfaces, meta.ActiveDescriptors          classProvides = [IComponentFactory],
           instancesProvide = [IComponent]
       )
   
   
       def __init__(self, parentComponent=NOT_GIVEN, componentName=None, **kw):
   
           # Set up keywords first, so state is sensible
           if kw:
               klass = self.__class__
               suggest = []; add = suggest.append; sPC = suggestParentComponent
   
               for kv in kw.iteritems():
                   k,v = kv
                   if hasattr(klass,k):
                       add(kv); setattr(self,k,v)
                   else:
                       raise TypeError(
                           "%s constructor has no keyword argument %s" %
                           (klass, k)
     )      )
   
     # use the global lookupComponent function as a method              # Suggest parents only after our attrs are stable
               for k,v in suggest:
                   sPC(self,k,v)
   
           # set our parent component and possibly invoke assembly events
           if parentComponent is not NOT_GIVEN or componentName is not None:
               self.setParentComponent(parentComponent,componentName)
   
     lookupComponent = lookupComponent      lookupComponent = lookupComponent
   
     def setParentComponent(self,parent):  
         from weakref import ref  
         self.getParentComponent = ref(parent)  
   
     def getParentComponent(self):  
         return None  
   
     def _componentName(self, dict, name):  
         return self.__class__.__name__.split('.')[-1]  
   
     _componentName = Once(_componentName)  
   
     __instance_provides__ = New(EigenRegistry)      def fromZConfig(klass, section):
   
     __class_provides__ = EigenRegistry()          """Classmethod: Create an instance from a ZConfig 'section'"""
   
           # ZConfig uses unicode for keys and defaults unsupplied values to None
           data = dict([(str(k),v) for k,v in section.__dict__.items()
               if v is not None])
   
           if not hasattr(klass,'_name') and '_name' in data:
               del data['_name']
   
           if not hasattr(klass,'_matcher') and '_matcher' in data:
               del data['_matcher']
   
           return klass(**data)
   
       fromZConfig = classmethod(fromZConfig)
   
   
       def setParentComponent(self, parentComponent, componentName=None,
           suggest=False):
   
           pc = self.__parentSetting
   
           if pc is NOT_GIVEN:
               self.__parentSetting = parentComponent
               self.__componentName = componentName
               self.__parentComponent  # lock and invoke assembly events
               return
   
           elif suggest:
               return
   
           raise AlreadyRead(
               "Component %r already has parent %r; tried to set %r"
               % (self,pc,parentComponent)
           )
   
       __parentSetting = NOT_GIVEN
       __componentName = None
   
       def __parentComponent(self,d,a):
   
     def acquireUtility(self, iface, forObj=None, localLookup=True):          parent = self.__parentSetting
           if parent is NOT_GIVEN:
               parent = self.__parentSetting = None
   
         if forObj is None:          d[a] = parent
             forObj=self          if parent is None:
               self.uponAssembly()
           elif (self.__class__.__attrsToBeAssembled__
               or self._getBinding('__objectsToBeAssembled__')):
                   notifyUponAssembly(parent,self)
   
         if localLookup:          return parent
   
             provider = self.__instance_provides__.get(iface)      __parentComponent = Once(__parentComponent)
   
             if provider is not None:  
                 return provider(self,forObj)  
   
             attr = self.__class_provides__.get(iface)      def getParentComponent(self):
           return self.__parentComponent
   
             if attr is not None:      def getComponentName(self):
           return self.__componentName
   
                 utility = getattr(self,attr)      __instance_provides__ = New(
           'peak.config.config_components:PropertyMap', provides=IPropertyMap
       )
   
                 if utility is not NOT_FOUND:  
                     return utility  
   
         parent = self.getParentComponent()  
   
         if parent is None:  
             parent = config.getLocal(self)  
   
         return parent.acquireUtility(iface,forObj)  
   
   
     def registerProvider(self, ifaces, provider):  
         self.__instance_provides__.register(ifaces, provider)  
   
   
   
Line 570 
Line 859 
   
   
   
       def _getConfigData(self, forObj, configKey):
   
           attr = self._getBinding('__instance_provides__')
   
 class AutoCreatable(type):          if attr:
               value = attr.getValueFor(forObj, configKey)
   
     """Metaclass for components which auto-create when used"""              if value is not NOT_FOUND:
                   return value
   
     def __get__(self, obj, typ=None):          attr = self.__class__.__class_provides__.get(configKey)
   
         if obj is None:          if attr:
             return self              return getattr(self, attr, NOT_FOUND)
   
         newOb = self(obj)          return NOT_FOUND
   
         obj.__dict__[newOb._componentName] = newOb  
         return newOb  
   
       def registerProvider(self, configKeys, provider):
           self.__instance_provides__.registerProvider(configKeys, provider)
   
 class AutoCreated(Component):  
   
     """Component that auto-creates itself in instances of its containing class      def notifyUponAssembly(self,child):
     """  
           tba = self.__objectsToBeAssembled__
   
           if tba is None:
               child.uponAssembly()    # assembly has already occurred
           else:
               tba.append(child)       # save reference to child for callback
   
               if (len(tba)==1 and self.__parentSetting is not NOT_GIVEN
                   and len(tba)==1 and not self.__class__.__attrsToBeAssembled__
               ):
                   # Make sure our parent calls us, since we need to call a
                   # child now, but would not have been registered ourselves.
                   notifyUponAssembly(self.getParentComponent(),self)
   
   
   
   
       def uponAssembly(self):
           """Don't override this unless you can handle the reentrancy issues!"""
           tba = self.__objectsToBeAssembled__
   
           if tba is None:
               return
   
           self.__objectsToBeAssembled__ = None
   
           try:
               while tba:
                   ob = tba.pop()
                   try:
                       ob.uponAssembly()
                   except:
                       tba.append(ob)
                       raise
   
     __metaclasses__ = AutoCreatable,              for attr in self.__class__.__attrsToBeAssembled__:
                   getattr(self,attr)
   
     def __init__(self, parent=None):          except:
               self.__objectsToBeAssembled__ = tba
               raise
   
         super(AutoCreated,self).__init__()      __objectsToBeAssembled__ = New(list)
   
         if parent is not None:  
             self.setParentComponent(parent)  
   
       def __attrsToBeAssembled__(klass,d,a):
           aa = {}
           map(aa.update, getInheritedRegistries(klass, '__attrsToBeAssembled__'))
   
           for attrName, descr in klass.__class_descriptors__.items():
               notify = getattr(descr,'activateUponAssembly',False)
               if notify: aa[attrName] = True
   
           return aa
   
       __attrsToBeAssembled__ = classAttr(Once(__attrsToBeAssembled__))
   
   
       def __class_provides__(klass,d,a):
   
           cp = EigenRegistry()
           map(cp.update, getInheritedRegistries(klass, '__class_provides__'))
   
           for attrName, descr in klass.__class_descriptors__.items():
               provides = getattr(descr,'declareAsProviderOf',None)
               if provides is not None:
                   cp.register(provides, attrName)
   
           cp.lock()   # make it immutable
           return cp
   
       __class_provides__ = classAttr(Once(__class_provides__))
   
   
   
 modules.setupModule()  
   
   
   Base = Component    # XXX backward compatibility; deprecated
   
   
   


Generate output suitable for use with a patch program
Legend:
Removed from v.469  
changed lines
  Added in v.1140

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help