def signature(self): """ return two-string tuple signature of (namespace, user or email); can be used as a composed key for storage implementations. Raises a zope.interface.Invalid exception if signature is not possible due to insufficient field data. """ IItemSubscriber.validateInvariants(self) # may raise Invalid... namespace = self.namespace identifier = self.user if self.email and not self.user: namespace = "email" # ignore field default identifier = self.email return (namespace, identifier)
def test_add_subscriber_email_only(self): # add by email, declare explicit namespace key = ("email", "*****@*****.**") self.container.add(namespace=key[0], email=key[1]) assert key in self.container sub = self.container[key] assert IItemSubscriber.providedBy(sub) IItemSubscriber.validateInvariants(sub) assert sub.email == key[1] assert sub.namespace == key[0] # add by email, should imply namespace self.container.add(email="*****@*****.**") assert ("email", "*****@*****.**") in self.container
def test_add_subscriber_copy(self): mock = MockSub() assert IItemSubscriber.providedBy(mock) key = ("member", "somebody") assert key not in self.container self.container.add(mock) assert key in self.container stored = self.container[key] assert IItemSubscriber.providedBy(stored) assert stored is not mock assert stored.__class__ is not mock.__class__ assert isinstance(stored, persistent.Persistent) assert isinstance(stored, ItemSubscriber) for fieldname in ("user", "namespace", "email", "name"): assert getattr(stored, fieldname) == getattr(mock, fieldname)
def add(self, *args, **kwargs): k = None fields = kwargs if not kwargs and len(args) == 1: v = args[0] if IItemSubscriber.providedBy(v): k = self._normalize_key(v) if isinstance(v, persistent.Persistent): self._set_new(k, v) return k, v fields = v.__dict__ # we'll copy values, not object to store # otherwise, assume a dict from args[0]: else: try: fields = dict(v) except ValueError: import sys exc_info = sys.exc_info() raise (KeyError, exc_info[1], exc_info[2]) # noqa v = ItemSubscriber(**fields) if k is None: k = self._normalize_key(v) self._set_new(k, v) return k, v
def __contains__(self, key): normalized = self._normalize_key(key) if IItemSubscriber.providedBy(key): if key is not super(SubscribersContainer, self).get(normalized, None): return False key = self._normalize_key(normalized) return super(SubscribersContainer, self).__contains__(normalized)
def __init__(self, context): if not IItemSubscriber.providedBy(context): raise ValueError('context must provided IItemSubscriber') self.context = context self.signature = context.signature() self.catalog = queryUtility(ISubscriptionCatalog) self.container = queryUtility(ISubscribers) if self.signature not in self.container: self.container.add(context)
def subscriptions_for(self, subscriber): """Find subscription names for a given subscriber for the context""" relnames = [] if IItemSubscriber.providedBy(subscriber): subscriber = subscriber.signature() for relname, index in self.catalog.indexes.items(): if subscriber in index.subscribers_for(self.uid): relnames.append(relname) return relnames
def _normalize_key(self, key): """ given key or object providing IItemSubscriber, normalize unique key """ if IItemSubscriber.providedBy(key): key = key.signature() elif isinstance(key, basestring): key = ("email", str(basestring)) if not (len(key) == 2 and key[0] and key[1]): raise KeyError("incomplete key for subscriber") return key
def __init__(self, **kwargs): """ Construct, if keyword arguments are used to construct, validate invariant on passed field values. """ if kwargs: user = kwargs.get("user", None) name = kwargs.get("name", None) namespace = kwargs.get("namespace", "member") email = kwargs.get("email", None) if isinstance(user, unicode): user = user.encode("utf-8") self.user = user if isinstance(email, unicode): email = email.encode("utf-8") self.email = email if isinstance(name, str): name = name.decode("utf-8") self.name = name if isinstance(namespace, unicode): namespace = namespace.encode("utf-8") self.namespace = namespace IItemSubscriber.validateInvariants(self)
def test_invariants(self): """Test interface invariants for IItemSubscriber""" verify = lambda sub: IItemSubscriber.validateInvariants(sub) # test empty email and user subscriber = ItemSubscriber() self.assertRaises(Invalid, verify, subscriber) # test email only subscriber.email = "*****@*****.**" self.fail_on_err(Invalid, verify, subscriber) # test both user and email subscriber.user = "******" self.fail_on_err(Invalid, verify, subscriber) # test user only subscriber.email = None self.fail_on_err(Invalid, verify, subscriber)
def index(self, name, subscriber): """ """ # ensure subscriber is in container of subscribers container = self.container if IItemSubscriber.providedBy(subscriber): if subscriber not in container: signature, subscriber = container.add(subscriber) else: if not (isinstance(subscriber, tuple) and len(subscriber)==2): raise ValueError('Subscriber signature malformed.') if subscriber not in container: #signature without backing item subscriber instance, so # create one. if subscriber[0] == 'email': container.add(namespace='email', email=str(subscriber[1])) else: container.add(namespace=subscriber[0], user=subscriber[1]) # index in catalog self.catalog.index(subscriber, self.uid, names=(name,))
def test_content_subscribers(self): """Content subscribers adapter search, index, unindex tests""" csubs = IContentSubscribers(self.content) relnames = ('invited', 'confirmed', 'attended') # test that there are no subscribers for any of the relnames for # content yet assert self.sub not in self.container #not yet, at least for name in relnames: assert len(csubs.find(name)) == 0 # index, and verify via find: csubs.index('invited', self.sub) assert self.sub in self.container # result of index through adapter assert self.sub in csubs.find('invited') assert 'invited' in csubs.subscriptions_for(self.sub) assert IItemSubscriber.providedBy(csubs.find('invited')[0]) assert len(csubs.find('confirmed')) == 0 assert len(csubs.find('attended')) == 0 assert len(csubs.find()) == 1 #unamed, one subscription so far # index another name: csubs.index('confirmed', self.sub) assert self.sub in csubs.find('invited') assert self.sub in csubs.find('confirmed') assert 'confirmed' in csubs.subscriptions_for(self.sub) assert self.sub in csubs.find() # unindex, make sure item is not found: csubs.unindex('invited', self.sub) assert self.sub not in csubs.find('invited') #removed assert 'invited' not in csubs.subscriptions_for(self.sub) assert self.sub in csubs.find('confirmed') #this still exists assert 'confirmed' in csubs.subscriptions_for(self.sub) # verify that we can look from the other direction at what we've done: subitems = ISubscriberItems(self.sub) assert self.content in subitems.find('confirmed') # finally, clean up: for name in relnames: csubs.unindex(name, self.sub) assert len(csubs.find(name)) == 0
def __setitem__(self, key, value): if not IItemSubscriber.providedBy(value): raise ValueError("__setitem__ value must provide IItemSubscriber") if key not in self: self.size.change(1) # increment super(SubscribersContainer, self).__setitem__(key, value)
def _normalize_subscriber(self, sub): """normalize subscriber or signature to signature""" if IItemSubscriber.providedBy(sub): sub = sub.signature() _validate_signature(sub) return sub