class SMTPFactory(binding.Singleton): protocols.advise(classProvides=[naming.IObjectFactory]) def getObjectInstance(self, context, refInfo, name, attrs=None): addr, = refInfo.addresses addr = adapt(addr, smtpURL) return smtplib.SMTP(addr.host, addr.port)
class _StringAsRecipe(_TypeAsRecipe): """ADAPTER: string (import spec) --> IRecipe""" protocols.advise(instancesProvide=[IRecipe], asAdapterForTypes=[str]) def __call__(self, component, instDict, attrName): return adapt(importString(self.subject), IRecipe)(component, instDict, attrName) def __repr__(self): return self.subject
class _TypeAsRecipe: """ADAPTER: type | class --> IRecipe""" protocols.advise(instancesProvide=[IRecipe], asAdapterForTypes=[type, ClassType]) def __init__(self, ob): self.subject = ob self.__doc__ = None # Don't use the type's docstring as our docstring def __call__(self, component, instDict, attrName): return self.subject() def __repr__(self): return "%s.%s" % (self.subject.__module__, self.subject.__name__)
class _MultiRecipe: """ADAPTER: Sequence(IRecipe) --> IRecipe""" protocols.advise(instancesProvide=[IRecipe], asAdapterForProtocols=[protocols.sequenceOf(IRecipe)]) def __init__(self, ob): self.subject = ob self.__doc__ = getattr(ob, '__doc__', None) def __repr__(self): return repr(self.subject) def __call__(self, component, instDict, attrName): return tuple( [ob(component, instDict, attrName) for ob in self.subject])
class LockFileBase: """Common base for lockfiles""" protocols.advise(instancesProvide=[ILock], classProvides=[naming.IObjectFactory]) def __init__(self, fn): self.fn = os.path.abspath(fn) self._lock = allocate_lock() self._locked = False def attempt(self): if self._lock.acquire(False): r = False try: r = self.do_acquire(False) finally: if not r and self._lock.locked(): self._lock.release() return r else: return False def obtain(self): self._lock.acquire() r = False try: r = self.do_acquire(True) finally: if not r and self._lock.locked(): self._lock.release() if not r: raise RuntimeError, "lock obtain shouldn't fail!" def release(self): self.do_release() self._locked = False self._lock.release() def locked(self): return self._locked def getObjectInstance(klass, context, refInfo, name, attrs=None): url, = refInfo.addresses return klass(url.getFilename()) getObjectInstance = classmethod(getObjectInstance)
class ActiveClass(Activator): """Metaclass for classes that are themselves components""" protocols.advise(instancesProvide=[IActiveDescriptor]) def activateInClass(self, klass, attrName): if klass.__module__ == self.__module__: if '__parent__' not in self.__dict__ and attrName != '__metaclass__': # We use a tuple, so that if our parent is a descriptor, # it won't interfere when our instance tries to set *its* # parent! self.__parent__ = klass, return self def __parent__(self, d, a): parent = self.__module__ name = self.__name__ if '.' in name: name = '.'.join(name.split('.')[:-1]) parent = '%s:%s' % (parent, name) return importString(parent), __parent__ = Make(__parent__, suggestParent=False) def __cname__(self, d, a): return self.__name__.split('.')[-1] __cname__ = Make(__cname__, suggestParent=False) def __all_descriptors__(klass): ad = {} map(ad.update, getInheritedRegistries(klass, '__all_descriptors__')) ad.update(klass.__class_descriptors__) return ad __all_descriptors__ = Make(__all_descriptors__, suggestParent=False)
class FacadeDM(binding.Component): """DM that just returns objects from other DM(s) via a different key""" protocols.advise( instancesProvide=[IKeyableDM] ) def __getitem__(self, oid, state=None): ob = self.cache.get(oid,self) if ob is not self: # double-check identity if oid==self.oidFor(ob): return ob # Oops, key no longer valid, drop it del self.cache[oid] ob = self._retrieve(oid, state) if ob is not None: self.cache[oid] = ob return ob raise KeyError, oid preloadState = __getitem__ cache = binding.Make('peak.storage.caches:WeakCache') def _retrieve(self, oid, state=None): """Look up 'oid' in underlying storage and return it, or 'None'""" raise NotImplementedError def oidFor(self, ob): """Return this DM's OID for 'ob'; used to validate consistency""" raise NotImplementedError
class EntityDM(QueryDM): protocols.advise( instancesProvide=[IWritableDM] ) def oidFor(self, ob): if ob._p_jar is self: oid = ob._p_oid if oid is None: # force it to have an ID by saving it ob._p_changed = 1 self.flush(ob) return ob._p_oid else: return oid else: return self._thunk(ob) def newItem(self,klass=None): if klass is None: klass = self.defaultClass if klass is None: raise NotImplementedError ob=klass() ob.__setstate__(self._defaultState(ob)) self.add(ob) return ob # Set/state management dirty = binding.Make(dict) saved = binding.Make(dict) to_delete = binding.Make(list) def flush(self, ob=None): markSaved = self.saved.setdefault dirty = self.dirty orig_ob = ob if ob is None: obs = dirty.values() else: obs = [ob] for ob in obs: if ob._p_oid is None: # No oid, it's a new object that needs saving oid = ob._p_oid = self._new(ob) self.cache[oid]=ob else: # just save it the ordinary way self._save(ob) # Update status flags and object sets key = id(ob) markSaved(key,ob) if key in dirty: del dirty[key] ob._p_changed = False if orig_ob is None and self.to_delete: self._delete_oids(self.to_delete) del self.to_delete # Private abstract methods/attrs defaultClass = None def _save(self, ob): raise NotImplementedError def _new(self, ob): raise NotImplementedError def _defaultState(self, ob): return ob.__getstate__() def _thunk(self, ob): raise NotImplementedError def _delete_oids(self,oidList): raise NotImplementedError def _check(self,ob): """Override this to raise an error if 'ob' is unsuitable for storing""" # Persistence.IPersistentDataManager methods def register(self, ob): # Ensure that we have a transaction service and we've joined # the transaction in progress... self.joinedTxn # precondition: # object has been changed since last save # postcondition: # ob is in 'dirty' set # DM is registered w/transaction if not previously registered key = id(ob) # Ensure it's in the 'dirty' set self.dirty.setdefault(key,ob) return self.joinedTxn # ITransactionParticipant methods def readyToVote(self, txnService): if self.dirty or self.to_delete: self.flush() return False else: return True def voteForCommit(self, txnService): # Everything should have been written by now... If not, it's VERY BAD # because the DB we're storing to might've already gotten a tpc_vote(), # and won't accept writes any more. So raise holy hell if we're dirty! assert not self.dirty and not self.to_delete def commitTransaction(self, txnService): self.saved.clear() self._delBinding('to_delete') def abortTransaction(self, txnService): for ob in self.dirty.values(): ob._p_changed = False ob._p_deactivate() self.dirty.clear() for ob in self.saved.values(): if ob._p_jar is self: # don't deactivate formerly-owned objects ob._p_deactivate() self.saved.clear() self._delBinding('to_delete') def add(self,ob): if not isinstance(ob,Persistent): raise TypeError("Not a persistent object", ob) if ob._p_jar is self: return # Nothing needed here elif ob._p_jar is not None: raise ValueError("Already in another DM", ob, ob._p_jar) self._check(ob) if ob._p_oid is not None: if self.get(ob._p_oid) is not None: raise InvalidKeyError("Duplicate key", ob._p_oid) self.cache[ob._p_oid] = ob ob._p_jar = self self.register(ob) def remove(self,ob): if ob._p_jar is not self: raise ValueError("Doesn't belong to this DM", ob, ob._p_jar) key = id(ob) if key in self.dirty: del self.dirty[key] # note: don't delete from 'saved', because we might still need to roll # back the object's state if it gets re-added, but the txn aborts, and # we don't have 'resetStatesAfterTxn' set. del self.cache[ob._p_oid] ob._p_jar = None self.to_delete.append(ob._p_oid) # Ensure that we have a transaction service and we've joined # the transaction in progress... self.joinedTxn
class QueryDM(TransactionComponent): resetStatesAfterTxn = True protocols.advise( instancesProvide=[IDataManager] ) to_delete = () def __getitem__(self, oid, state=None): if self.resetStatesAfterTxn: # must always be used in a txn self.joinedTxn if oid in self.to_delete: raise InvalidKeyError("Reference to deleted key", oid) ob = self.cache.get(oid,self) if ob is not self: return ob ob = self._ghost(oid,state) if isinstance(ob,Persistent): ob._p_jar = self ob._p_oid = oid if state is None: ob._p_deactivate() else: ob.__setstate__(state) self.cache[oid] = ob return ob preloadState = __getitem__ # Private abstract methods/attrs cache = binding.Make('peak.storage.caches:WeakCache') defaultClass = PersistentQuery def _ghost(self, oid, state=None): klass = self.defaultClass if klass is None: raise NotImplementedError return klass() def _load(self, oid, ob): raise NotImplementedError # Persistence.IPersistentDataManager methods def setstate(self, ob): if self.resetStatesAfterTxn: # must always be used in a txn self.joinedTxn oid = ob._p_oid assert oid is not None ob.__setstate__(self._load(oid,ob)) def mtime(self, ob): pass # return None def register(self, ob): raise TypeError("Attempt to modify query result", ob) # ITransactionParticipant methods def finishTransaction(self, txnService, committed): if self.resetStatesAfterTxn: for oid, ob in self.cache.items(): if isinstance(ob,Persistent): ob._p_deactivate() super(QueryDM,self).finishTransaction(txnService,committed) # Misc. def __iter__(self): raise NotImplementedError def __contains__(self, ob): if isinstance(ob,Persistent): return ob._p_jar is self return self.get(ob) is not None def get(self,oid,default=None): if self.resetStatesAfterTxn: # must always be used in a txn self.joinedTxn if oid in self.cache: return self.cache[oid] elif oid in self.to_delete: return default try: state = self._load(oid,None) except InvalidKeyError: return default else: return self.preloadState(oid,state)
of on framework-oriented concerns. """ from peak.util.imports import importObject from peak.api import adapt, protocols from interfaces import * from names import NNS_Reference from peak.binding.interfaces import IComponentFactory __all__ = [ 'getInitialContext', 'getURLContext', ] protocols.advise(moduleProvides=[IURLContextFactory, IInitialContextFactory]) def getInitialContext(parentComponent, componentName=None, **options): """Create initial context for parent, w/component name and options The type of initial context created is determined by asking the supplied 'parentComponent' for its 'peak.naming.initialContextFactory' property, which will be treated as an import string if it is of string type. (Note: the property name used is available as the constant 'naming.INIT_CTX_FACTORY', if you want to provide an attribute binding for it.) Keyword options and the component name desired for the initial context are passed through to the actual factory, along with the parent component and component name. If a 'creationParent' argument is not supplied,
class CacheBase(binding.Component): protocols.advise(instancesProvide=[ICache])
class Attribute(Descriptor): """Descriptor for Component Attribute Bindings 'Attribute' is a 'Descriptor' with additional features to make component interconnection easier. Specifically, 'Attribute' adds the ability to automatically adapt computed or assigned values to a specific interface, and the ability to automatically "suggest" to an assigned value that the containing object should become its parent component. In addition, 'Attribute' has various metadata attributes that can be read by a containing class, to enable various features such as "offering" the attribute as a supplier of a particular interface or configuration key. In addition, if an 'Attribute' is placed in a 'binding.Component' subclass (or any class whose metaclass derives from 'binding.Activator'), it will automatically discover its 'attrName' from the class, so that you don't have to explicitly supply it. 'Attribute' is primarily an abstract base class; you will ordinarily use 'Make', 'Obtain', 'Require', or 'Delegate' instead. However, all of those subclasses accept the same keyword arguments, and have the same basic lazy initialization and caching behavior. They differ only in *how* they compute the attribute value, and in their constructors' positional arguments. In addition to the attributes defined by the 'Descriptor' base class, 'Attribute' instances also have the following attributes, which may be overridden in subclasses, or by supplying constructor keyword arguments: 'offerAs' -- A sequence of configuration keys under which the attribute should be registered. This tells the containing 'Component' class to offer the attribute's value to child components when they look up any of the specified configuration keys. Values in the supplied sequence will be adapted to the 'config.IConfigKey' interface. Default value: an empty list. (Note that this attribute has no effect unless the 'Attribute' is placed in a 'binding.Component' subclass.) 'uponAssembly' -- A flag indicating whether the attribute should be initialized as soon as its containing component is part of a complete component hierarchy. Default value: False. (Note that this attribute has no effect unless the 'Attribute' is placed in a 'binding.Component' subclass.) 'doc' -- A docstring, used to give an appropriate representation of the attribute when it's rendered by 'pydoc' or the Python 'help()' function. 'adaptTo' -- the interface that values of this attribute should be adapted to, or 'None'. If not 'None', then whenever the attribute is set (or its 'computeValue()' result is cached), the value will be adapted to this interface before being stored. If adaptation fails, a 'NotImplementedError' will be raised. (Note that this behavior is implemented by 'Attribute.onSet()'; if you override the default 'onSet()', this adaptation will not take place unless your replacement does it.) 'suggestParent' -- should assigned values be informed that they are being attached to the containing component? This value defaults to 'True', so you should set it to 'False' if you do not want the attachment to happen. If 'True', then whenever the attribute is set (or its 'computeValue()' result is cached), 'suggestParentComponent()' will be called to let the value know that the containing component may be the value's parent component, and what attribute name it is being referenced by. Note that this call happens *after* the value is first adapted to the 'adaptTo' interface, if applicable, and is also performed by 'Attribute.onSet()', so the same warning about overriding 'onSet()' applies here. """ __metaclass__ = AttributeClass protocols.advise(instancesProvide=[IActiveDescriptor]) # XXX Set up 'activateUponAssembly' to set the 'uponAssembly' attribute # XXX This is for backward compatibility only, and should go away in a4 activateUponAssembly = Descriptor( attrName='activateUponAssembly', onSet=lambda o, a, v: setattr(o, 'uponAssembly', v and 1 or 0) or v, computeValue=lambda o, d, a: False) offerAs = () uponAssembly = False doc = None adaptTo = None suggestParent = True metadata = None def activateInClass(self, klass, attrName): setattr(klass, attrName, self._copyWithName(attrName)) declareAttribute(klass, attrName, self.metadata) declareAttribute(klass, attrName, self.permissionNeeded) # XXX return self def _copyWithName(self, attrName): return Descriptor(attrName=attrName, computeValue=self.computeValue, ofClass=self.ofClass, onSet=self.onSet, noCache=self.noCache, permissionNeeded=self.permissionNeeded) def __repr__(self): if self.__doc__: return "binding.Attribute:\n\n%s" % self.__doc__ else: return "binding.Attribute()" def onSet(self, obj, attrName, value): if self.adaptTo is not None: value = adapt(value, self.adaptTo) if self.suggestParent: suggestParentComponent(obj, attrName, value) return value # The following methods only get called when an instance of this class is # used as a descriptor in a classic class or other class that doesn't # support active descriptors. So, we will use the invocation of these # methods to bootstrap our activation. Once activated, these methods won't # be called any more. def __get__(self, ob, typ=None): if ob is None: return self return self._installedDescr(ob.__class__).__get__(ob, typ) def __set__(self, ob, value): self._installedDescr(ob.__class__).__set__(ob, value) def __delete__(self, ob, value): self._installedDescr(ob.__class__).__delete__(ob) def _installedDescr(self, klass): # Return a newly installed descriptor proxy to use, or raise a usage # error if self doesn't know its own right name. from protocols.advice import getMRO name = self.attrName for cls in getMRO(klass): if name in cls.__dict__: if cls.__dict__[name] is self: # Install a proxy, so we don't have to do this again! descr = self._copyWithName(name) setattr(cls, name, descr) return descr else: break # If we get here, we were not found under the name we were given self.usageError()
class Base(Struct): """Basic scheme/body URL""" protocols.advise(instancesProvide=[IAddress], classProvides=[IAddressFactory]) nameKind = URL_KIND nameAttr = None supportedSchemes = () def supportsScheme(klass, scheme): return scheme in klass.supportedSchemes or not klass.supportedSchemes supportsScheme = classmethod(supportsScheme) def __init__(self, scheme=None, body='', **__kw): scheme = scheme or self.__class__.defaultScheme if body: data = self.parse(scheme, str(body)) data.update(__kw) __kw = data __kw['scheme'] = scheme __kw['body'] = body for f in self.__class__.mdl_features: if f.isRequired and not f.attrName in __kw: raise exceptions.InvalidName("Missing %s field in %r" % (f.attrName, __kw)) super(Base, self).__init__(**__kw) self.__class__.body._setup(self, self.getCanonicalBody()) class scheme(RequiredField): _defaultValue = classAttr(Obtain('defaultScheme')) def _onLink(feature, element, item, posn): # delegate scheme validation to element class if not element.supportsScheme(item): raise exceptions.InvalidName("Unsupported scheme %r for %r" % (item, element.__class__)) class body(NameField): defaultValue = '' unquote = False canBeEmpty = True syntax = body._syntax # default syntax is just to parse the body def mdl_fromString(klass, aName): m = URLMatch(aName) if m: return klass(m.group(1), aName[m.end():]) else: return klass(None, aName) def __str__(self): return "%s:%s" % (self.scheme, self.body) # "inherit" findComponent() method from names findComponent = CompoundName.findComponent.im_func __add__ = name_add __sub__ = name_sub __radd__ = name_radd __rsub__ = name_rsub def addName(self, other): if not other: return self name = adapt(other, IName, None) if name is None: raise TypeError("Only names can be added to URLs", self, other) other = name if other.nameKind == URL_KIND: return other na = self.nameAttr if not na: raise TypeError("Addition not supported for pure address types", self, other) d = dict(self._hashAndCompare) d['body'] = None # before the below in case 'na' is "body" d[na] = getattr(self, na, CompoundName(())) + other res = self.__class__(**d) return res def __split(self): d = dict(self._hashAndCompare) na = self.nameAttr if na: if na in d: nic = d[na] del d[na] else: nic = getattr(self, na) else: nic = CompoundName(()) d['body'] = '' auth = self.__class__(**d) return auth, nic __split = Make(__split) def getAuthorityAndName(self): return self.__split def __repr__(self): return "%s(%s)" % (self.__class__.__name__, ','.join( ['%s=%r' % (k, v) for (k, v) in self._hashAndCompare])) def _hashAndCompare(self): klass = self.__class__ omitBody = len(klass.mdl_featureNames) != 2 # ('scheme','body') return tuple([(f, getattr(self, f)) for f in self.__class__.mdl_featureNames if (not omitBody or f != 'body')]) _hashAndCompare = Make(_hashAndCompare) def parse(klass, scheme, body): if klass.syntax is not None: return parse(body, klass.syntax) return {} parse = classmethod(parse) def getCanonicalBody(self): if self.__class__.syntax is not None: return format(dict(self._hashAndCompare), self.__class__.syntax) return self.body defaultScheme = classAttr( Make(lambda self: self.supportedSchemes and self.supportedSchemes[0] or None)) def getURLContext(klass, parent, scheme, iface, componentName=None, **options): if klass.supportsScheme(scheme): from contexts import AddressContext return AddressContext(parent, componentName, schemeParser=klass, **options) getURLContext = classmethod(getURLContext) def __adapt__(klass, ob): """Allow address classes to be used as protocols""" if isinstance(ob, str): return klass.mdl_fromString(ob) __adapt__ = classAttr(protocols.metamethod(__adapt__))