[Subversion] / PEAK / src / peak / naming / contexts.py  

View of /PEAK/src/peak/naming/contexts.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: 8791 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.
"""Base classes for naming contexts"""

from interfaces import *
from names import *
from references import *
from peak.binding.imports import importObject
from peak.binding.components import Component, bindTo, Once
from peak import exceptions

import spi

_marker = object()

__all__ = ['AbstractContext', 'BasicInitialContext', 'GenericURLContext']



























class AbstractContext(Component):

    __implements__ = IBasicContext

    _supportedSchemes = ()

    _acceptURLs = 1

    _makeName = CompoundName

    _allowCompositeNames = 0

    creationParent = bindTo(IParentForRetrievedObject)

    def __init__(self, parent=None, **kw):
        if kw:
            self.__dict__.update(kw)
        if parent is not None:
            self.setParentComponent(parent)

    def close(self):
        pass

    def __del__(self):
        self.close()
















    def _getTargetCtx(self, name, iface=IBasicContext):

        name = toName(name, self._makeName, self._acceptURLs)

        if name.isComposite:
        
            if self._allowCompositeNames:
                return self, name
                
            else:
                # convert to URL
                name=OpaqueURL('+:'+str(name))


        if name.isURL:

            if self._supportsScheme(name.scheme):
            
                if not isinstance(name,ParsedURL):
                    name = self._makeName(name)

                return self, name

            ctx = spi.getURLContext(name.scheme, self, iface)

            if ctx is None:
                raise exceptions.InvalidName(
                    "Unknown scheme %s in %r" % (name.scheme,name)
                )

            return ctx, name

        return self, name








    def lookup_nns(self, name=None):

        """Find the next naming system after resolving local part"""

        if name is None:

            return self._deref(
                NNS_Reference( self ), name, None
            )

        obj = self[name]

        if isinstance(obj,self.__class__):
          
            # Same or subclass, must not be a junction;
            # so delegate the NNS lookup to it
            
            return obj.lookup_nns()


        elif not IBasicContext.isImplementedBy(obj):
            
            # Not a context?  make it an NNS reference

            return self._deref(
                NNS_Reference( obj ), name, None
            )

        else:
            # It's a context, so just return it
            return obj


    def _supportsScheme(self, scheme):
        return scheme.lower() in self._supportedSchemes






    def _deref(self, state, name, attrs=None):

        return spi.getObjectInstance(
            state, name, self, attrs
        )


    def lookupLink(self, name):

        """Return terminal link for 'name'"""

        ctx, name = self._getTargetCtx(name)
        if ctx is not self: return ctx.lookupLink(name)

        info = self._get(name,_marker)
        
        if info is _marker:
            raise exceptions.NameNotFound(name)

        state, attrs = info

        if isinstance(state,LinkRef):
            return state

        return self._deref(state, name, attrs)


    def __getitem__(self, name):
    
        """Lookup 'name' and return an object"""
        
        ctx, name = self._getTargetCtx(name)
        if ctx is not self: return ctx[name]
        
        obj = self._getOb(name,_marker)
        if obj is _marker:
            raise exceptions.NameNotFound(name)

        return obj


    def get(self, name, default=None):
    
        """Lookup 'name' and return an object, or 'default' if not found"""
        
        ctx, name = self._getTargetCtx(name)
        if ctx is not self: return ctx.get(name,default)

        return self._getOb(name, default)


    def _getOb(self, name, default):

        info = self._get(name,default)
        if info is default: return info

        state, attrs = info

        return self._deref(state, name, attrs)


    def __contains__(self, name):
        """Return a true value if 'name' has a binding in context"""

        ctx, name = self._getTargetCtx(name)
        
        if ctx is not self:
            return name in ctx

        return self._get(name, _marker, retrieve=False) is not _marker


    def lookup(self, name):
        """Lookup 'name' --> object; synonym for __getitem__"""
        return self[name]

    def has_key(self, name):
        """Synonym for __contains__"""
        return name in self



    def keys(self):
        """Return a sequence of the names present in the context"""
        return [name for name in self]
        
    def items(self):
        """Return a sequence of (name,boundItem) pairs"""
        return [ (name,self._getOb(name, None)) for name in self ]

    def info(self):
        """Return a sequence of (name,refInfo) pairs"""
        return [ (name,self._get(name,retrieve=False))
                    for name in self
        ]

    def bind(self, name, object, attrs=None):

        """Synonym for __setitem__, with attribute support"""

        self.__setitem__(name,object,attrs)

    def unbind(self, name, object):

        """Synonym for __delitem__"""

        del self[name]


    def rename(self, oldName, newName):

        """Rename 'oldName' to 'newName'"""

        ctx, name = self._getTargetCtx(oldName,IWriteContext)
        
        if ctx is not self:
            ctx.rename(oldName,newName)
            return
            
        ctx, newName = self._getTargetCtx(newName)
       
        self._rename(name,newName)

    def __setitem__(name, object, attrs=None):

        """Bind 'object' under 'name'"""

        ctx, name = self._getTargetCtx(name,IWriteContext)
        
        if ctx is not self:
            ctx[name]=object

        else:
            
            state,bindattrs = spi.getStateToBind(
                object,name,self,attrs
            )

            self._bind(name, state, bindAttrs)


    def __delitem__(self, name):
        """Remove any binding associated with 'name'"""

        ctx, name = self._getTargetCtx(name,IWriteContext)
        
        if ctx is not self:
            del ctx[name]
        else:
            self._unbind(name)














    # The actual implementation....

    def _get(self, name, default=None, retrieve=1):

        """Lookup 'name', returning 'default' if not found

        If 'retrieve' is true, return a '(state,attrs)' tuple of binding info.
        Otherwise, return any true value that is not 'default'.  In either
        case, return 'default' if the name is not bound.
        """

        raise NotImplementedError


    def __iter__(self):
        """Return an iterator of the names present in the context

        Note: must return names which are directly usable by _get()!  That is,
        ones which have already been passed through toName() and/or
        self._makeName().
        """        
        raise NotImplementedError


    def _bind(self, name, state, attrs=None):
        raise NotImplementedError


    def _unbind(self, name):
        raise NotImplementedError


    def _rename(self, old, new):
        raise NotImplementedError







class GenericURLContext(AbstractContext):

    """Handler for address-only URL namespaces"""

    def _getParserFor(self, scheme):
        from factories import schemeParsers
        return importObject(schemeParsers.get(scheme.lower()))


    def _getTargetCtx(self, name, iface=IBasicContext):

        name = toName(name)

        if name.isComposite:        
            # convert to URL
            name = OpaqueURL('+:'+str(name))

        if name.isURL:
            parser = self._getParserFor(name.scheme)
            
            if parser is not None:            
                return self, parser.fromURL(name)

            ctx = spi.getURLContext(name.scheme, self, iface)

            if ctx is None:
                raise exceptions.InvalidName(
                    "Unknown scheme %s in %r" % (name.scheme,name)
                )

            return ctx, name

        raise exceptions.InvalidName("Not a URL:", name)


    def _get(self, name, default=None, retrieve=1):
        return (name, None)     # refInfo, attrs




class BasicInitialContext(AbstractContext):

    def creationParent(self, d, a):

        """Default binding for 'creationParent' is the nearest LocalConfig

        Note that you should normally supply 'creationParent=someObj' as a
        keyword option to 'naming.InitialContext()' to explicitly set the
        creation parent.  But if you don't, the default creation parent is
        'config.getLocal(theNewInitialContext)'."""

        from peak.config.api import getLocal
        return getLocal(self)

    creationParent = Once(creationParent)

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help