[Subversion] / PEAK / src / peak / config / config_components.py  

View of /PEAK/src/peak/config/config_components.py

Parent Directory | Revision Log
Revision: 555 - (download) (as text)
Fri Oct 11 00:53:50 2002 UTC (21 years, 6 months ago) by pje
File size: 4459 byte(s)
Properties and utilities are unified at last!  Both properties and
utilities are now handled by the __instance_provides__ and
__class_provides__ attributes of component classes.  This simplified the
code and interfaces for both PropertyMap and for registering dynamic
utility providers.

Property names now have an additional syntax form: 'some.prop?' which is
used as a default value that is checked after 'some.prop', 'some.*', and
'some.prop' (a second time).  This is handled transparently for you by
way of the 'setDefault()' method of 'IPropertyMap', so effectively it's an
implementation detail.

Documentation is still a little sketchy, but it should now be
straightforward to get the naming system using properties and utilities in
a harmonious way.


ALSO:

Fixed config.getLocal() to ensure it's working with a root component.
binding.New() can now use an import string instead of a
class/type/callable.  The object referenced by the import string will be
loaded and called as though the object itself had been used.  GlobalConfig
and LocalConfig now have 'setup()' methods that can be overridden to
create default rule and provider registrations.  This'll be handy for
making LocalConfig register a default transaction service provider, for
example.
from __future__ import generators

from peak.binding.components import Component, New, AutoCreated

from peak.api import NOT_FOUND, NOT_GIVEN
from peak.util.EigenData import EigenCell, AlreadyRead

from interfaces import *
from Interface import Interface

__all__ = [
    'GlobalConfig', 'LocalConfig', 'PropertyMap', 'LoadingRule',
]


def _setCellInDict(d,key,value):

    cell = d.get(key)

    if cell is None:
        cell = d[key] = EigenCell()

    cell.set(value)


_emptyRuleCell = EigenCell()
_emptyRuleCell.set(lambda *args: NOT_FOUND)
_emptyRuleCell.exists()













class PropertyMap(AutoCreated):

    rules     = New(dict)
    provided  = New(dict)   
    _provides = IPropertyMap


    def setRule(self, propName, ruleFactory):
        ruleObj = ruleFactory(self, propName)
        _setCellInDict(self.rules, Property(propName), ruleObj)

    def setDefault(self, propName, defaultRule):
        _setCellInDict(self.rules, Property(propName+'?'), defaultRule)

    def setValue(self, propName, value):
        _setCellInDict(self.rules, Property(propName), lambda *args: value)

    def registerProvider(self, ifaces, provider):

        """Register 'item' under 'implements' (an Interface or nested tuple)"""

        if isinstance(ifaces,tuple):
            for iface in ifaces:
                self.registerProvider(iface,provider)
        else:
            self._register(ifaces,provider,ifaces)

    def _register(self, iface, item, primary_iface):

        old = self.provided.get(iface)

        # We want to keep more-general registrants
        if old is None or old.extends(primary_iface):
        
            _setCellInDict(self.rules, iface, item)
            self.provided[iface]=primary_iface

            for base in iface.getBases():
                if base is not Interface:
                    self._register(base,item,primary_iface)

    def getValueFor(self, configKey, forObj=None):

        rules      = self.rules
        value      = NOT_FOUND

        if not rules:
            return value

        xRules     = []

        if isinstance(configKey,Property):
            lookups = configKey.matchPatterns()
        else:
            lookups = configKey,


        for name in lookups:

            rule = rules.get(name)

            if rule is None:
                xRules.append(name)     # track unspecified rules

            elif rule is not _emptyRuleCell:

                value = rule.get()(self, configKey, forObj)

                if value is not NOT_FOUND:
                    break

        # ensure that unspecified rules stay that way, if they
        # haven't been replaced in the meanwhile by a higher-level
        # wildcard rule

        for name in xRules:
            rules.setdefault(name,_emptyRuleCell)
       
        return value



class LoadingRule(object):

    def __init__(self, loadFunc, **kw):
        self.load = loadFunc
        self.__dict__.update(kw)

    def __call__(self, propertyMap, propName):

        mask = propName

        assert mask.endswith('*'), "LoadingRules are for wildcard rules only"
        prefix = mask[:-1]

        if prefix and not prefix.endswith('.'):
            prefix+='.'
        
        def compute(propertyMap, propName, targetObj):

            if compute.loadNeeded:

                try:
                    compute.loadNeeded = False
                    return self.load(self, propertyMap, prefix, propName)
                except:
                    compute.loadNeeded = True
                    raise

            return NOT_FOUND

        compute.loadNeeded = True
        return compute


def loadEnviron(factory, pMap, prefix, name):
    from os import environ

    for k,v in environ.items():
        pMap.setValue(prefix+k, v)

    return NOT_FOUND

class GlobalConfig(Component):

    def __init__(self):
        self.setup()

    def setup(self):
        self.__instance_provides__.setRule(
            'environ.*', LoadingRule(loadEnviron)
        )

    def setParentComponent(self,parent):
        raise TypeError("Global config can't have a parent")



class LocalConfig(Component):

    def __init__(self,parent):
        self.setParentComponent(parent)
        self.setup()

    def setup(self):
        pass

    def setParentComponent(self,parent):

        assert isinstance(parent,GlobalConfig), \
            "LocalConfig parent must be GlobalConfig"

        super(LocalConfig,self).setParentComponent(parent)



cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help