def test_default(self): # First default wins from left to right def1 = default(1) self.assertTrue(def1 + def1 is def1) def2 = default(2) self.assertTrue(def1 + def2 is def1) self.assertTrue(def2 + def1 is def2) # Override wins over default ext3 = override(3) self.assertTrue(def1 + ext3 is ext3) # Finalize wins over default fin4 = finalize(4) self.assertTrue(def1 + fin4 is fin4) # Adding with something else than default/override, raises # ``PlumbingCollision`` err = None try: def1 + Instruction('foo') except PlumbingCollision as e: err = e finally: self.assertEqual(err.left.__class__.__name__, 'default') self.assertEqual(err.left.payload, 1) self.assertEqual(err.right.__class__.__name__, 'Instruction') self.assertEqual(err.right.payload, 'foo')
def test_finalize(self): # First override wins against following equal overrides and arbitrary # defaults fin1 = finalize(1) self.assertTrue(fin1 + fin1 is fin1) self.assertTrue(fin1 + finalize(1) is fin1) self.assertTrue(fin1 + default(2) is fin1) self.assertTrue(fin1 + override(2) is fin1) # Two unequal finalize collide err = None try: fin1 + finalize(2) except PlumbingCollision as e: err = e finally: self.assertEqual(err.left.__class__.__name__, 'finalize') self.assertEqual(err.left.payload, 1) self.assertEqual(err.right.__class__.__name__, 'finalize') self.assertEqual(err.right.payload, 2) # Everything except default/override collides try: fin1 + Instruction(1) except PlumbingCollision as e: err = e finally: self.assertEqual(err.left.__class__.__name__, 'finalize') self.assertEqual(err.left.payload, 1) self.assertEqual(err.right.__class__.__name__, 'Instruction') self.assertEqual(err.right.payload, 1)
class Behavior3(Behavior): def set_foo(self, value): self._foo = value foo = plumb(property( None, override(set_foo), ))
class OverlayForm(Behavior): """Form behavior rendering to overlay. """ action_resource = override('overlayform') overlay_selector = override('#ajax-overlay') overlay_content_selector = override('.overlay_content') @plumb def __call__(_next, self, model, request): form = _next(self, model, request) selector = '%s %s' % (self.overlay_selector, self.overlay_content_selector) ajax_form_fiddle(request, selector, 'inner') return form @default def next(self, request): return [AjaxOverlay(selector=self.overlay_selector, close=True)]
class ContentAddForm(AddFactoryProxy, AddFormHeading, ContentForm, CameFromNext): """Form behavior rendering add form to content area. """ action_resource = override('add') @default @property def rendered_contextmenu(self): return render_tile(self.model.parent, self.request, 'contextmenu')
def test_override(self): # First override wins against following equal overrides and arbitrary # defaults ext1 = override(1) self.assertTrue(ext1 + ext1 is ext1) self.assertTrue(ext1 + override(1) is ext1) self.assertTrue(ext1 + override(2) is ext1) self.assertTrue(ext1 + default(2) is ext1) fin3 = finalize(3) self.assertTrue(ext1 + fin3 is fin3) # Everything except default/override collides err = None try: ext1 + Instruction(1) except PlumbingCollision as e: err = e finally: self.assertEqual(err.left.__class__.__name__, 'override') self.assertEqual(err.left.payload, 1) self.assertEqual(err.right.__class__.__name__, 'Instruction') self.assertEqual(err.right.payload, 1)
class ChildFactory(Behavior): factories = default(odict()) @override def __iter__(self): return self.factories.__iter__() iterkeys = override(__iter__) @plumb def __getitem__(_next, self, key): try: child = _next(self, key) except KeyError: child = self.factories[key]() self[key] = child return child
class Nodify(FullMapping): __name__ = default(None) __parent__ = default(None) @plumb def copy(_next, self): new = _next(self) new.__name__ = self.__name__ new.__parent__ = self.__parent__ return new @override @property def name(self): return self.__name__ @override @property def parent(self): return self.__parent__ @override @property def path(self): path = [parent.name for parent in LocationIterator(self)] path.reverse() return path @override @property def root(self): root = None for parent in LocationIterator(self): root = parent return root @override def detach(self, key): node = self[key] del self[key] return node @override def acquire(self, interface): node = self.parent while node: if (IInterface.providedBy(interface) and interface.providedBy(node)) or \ isinstance(node, interface): return node node = node.parent @override def filtereditervalues(self, interface): for val in self.itervalues(): if interface.providedBy(val): yield val @override def filteredvalues(self, interface): return [val for val in self.filtereditervalues(interface)] # B/C 2010-12-23 filtereditems = override(filtereditervalues) @override @property def noderepr(self): """``noderepr`` is used in ``treerepr``. Thus, we can overwrite it in subclass and return any debug information we need while ``__repr__`` is an enhanced standard object representation, also used as ``__str__`` on nodes. """ class_name = self.__class__ name = self.name.encode('ascii', 'replace') \ if IS_PY2 and isinstance(self.name, unicode) \ else str(self.name) return str(class_name) + ': ' + name[name.find(':') + 1:] @override def treerepr(self, indent=0, prefix=' '): res = '{}{}\n'.format(indent * prefix, self.noderepr) items = self.items() \ if IOrdered.providedBy(self) \ else sorted(self.items(), key=lambda x: safe_decode(x[0])) for key, value in items: if INode.providedBy(value): res += value.treerepr(indent=indent + 2, prefix=prefix) else: res += '{}{}: {}\n'.format((indent + 2) * prefix, key, repr(value)) return res @override def printtree(self): print(self.treerepr()) # pragma: no cover @default def __nonzero__(self): return True __bool__ = default(__nonzero__) @override def __repr__(self): class_name = self.__class__.__name__ name = self.name.encode('ascii', 'replace') \ if IS_PY2 and isinstance(self.name, unicode) \ else str(self.name) return '<{} object \'{}\' at {}>'.format(class_name, name, hex(id(self))[:-1]) __str__ = override(__repr__)
class Reference(Behavior): _uuid = default(None) @plumb def __init__(_next, self, *args, **kw): self._index = dict() self.uuid = uuid.uuid4() _next(self, *args, **kw) @plumb def __setitem__(_next, self, key, val): if INode.providedBy(val): try: next(val.iterkeys()) keys = set(self._index.keys()) if keys.intersection(val._index.keys()): raise ValueError('Node with uuid already exists') except StopIteration: pass self._index.update(val._index) val._index = self._index _next(self, key, val) @plumb def __delitem__(_next, self, key): # fail immediately if key does not exist todel = self[key] if hasattr(todel, '_to_delete'): for iuuid in todel._to_delete(): del self._index[iuuid] _next(self, key) @plumb def detach(_next, self, key): node = _next(self, key) node._index = {int(node.uuid): node} node._index_nodes() return node def _get_uuid(self): return self._uuid def _set_uuid(self, uuid): iuuid = uuid is not None and int(uuid) or None if iuuid in self._index \ and self._index[iuuid] is not self: raise ValueError('Given uuid was already used for another Node') siuuid = self._uuid is not None and int(self._uuid) or None if siuuid in self._index: del self._index[siuuid] self._index[iuuid] = self self._uuid = uuid uuid = override(property(_get_uuid, _set_uuid)) @override @property def index(self): return NodeIndex(self._index) @override def node(self, uuid): return self._index.get(int(uuid)) @default def _to_delete(self): todel = [int(self.uuid)] for childkey in self: try: todel += self[childkey]._to_delete() except AttributeError: # Non-Node values or non referencing children are not told # about deletion. continue return todel @default def _index_nodes(self): for node in self.values(): try: uuid = int(node.uuid) except AttributeError: # non-Node values are a dead end, no magic for them continue self._index[uuid] = node node._index = self._index node._index_nodes()
class OverlayEditForm(OverlayForm, EditFormHeading): """Edit form behavior rendering to overlay. """ action_resource = override('overlayedit')
class ContentEditForm(EditFormHeading, ContentForm, CameFromNext): """Form behavior rendering edit form to content area. """ action_resource = override('edit')
class OverlayAddForm(OverlayForm, AddFactoryProxy, AddFormHeading): """Add form behavior rendering to overlay. """ action_resource = override('overlayadd')
class Behavior1(Behavior): K = override('Behavior1') M = override('Behavior1')
class Behavior2(Behavior): K = override('Behavior2') L = override('Behavior2') M = override('Behavior2')
class Nodify(FullMapping): __name__ = default(None) __parent__ = default(None) @plumb def copy(_next, self): new = _next(self) new.__name__ = self.__name__ new.__parent__ = self.__parent__ return new @override @property def name(self): return self.__name__ @override @property def parent(self): return self.__parent__ @override @property def path(self): path = [parent.name for parent in LocationIterator(self)] path.reverse() return path @override @property def root(self): root = None for parent in LocationIterator(self): root = parent return root @override def detach(self, key): node = self[key] del self[key] return node @override def acquire(self, interface): node = self.parent while node: if (IInterface.providedBy(interface) \ and interface.providedBy(node)) \ or isinstance(node, interface): return node node = node.parent @override def filtereditervalues(self, interface): """Uses ``itervalues``. """ for val in self.itervalues(): if interface.providedBy(val): yield val @override def filteredvalues(self, interface): """Uses ``values``. """ return [val for val in self.filtereditervalues(interface)] # BBB 2010-12-23 filtereditems = override(filtereditervalues) @override @property def noderepr(self): """``noderepr`` is used in ``printtree``. Thus, we can overwrite it in subclass and return any debug information we need while ``__repr__`` is an enhanced standard object representation, also used as ``__str__`` on nodes. XXX: do we really need the difference or can we just override __repr__ in subclasses and use __repr__ in printtree? """ # XXX: is this a relict from plumber prototyping? -rn #if hasattr(self.__class__, '_wrapped'): # class_ = self.__class__._wrapped #else: # class_ = self.__class__ class_ = self.__class__ name = unicode(self.__name__).encode('ascii', 'replace') return str(class_) + ': ' + name[name.find(':') + 1:] @override def printtree(self, indent=0): """Uses ``values``. """ print "%s%s" % (indent * ' ', self.noderepr) for node in self.values(): try: node.printtree(indent + 2) except AttributeError: # Non-Node values are just printed print "%s%s" % (indent * ' ', node) # XXX: tricky one: If a base class provides a __nonzero__ and that # base class is nodified, should the base class' __nonzero__ be # used or this one? Please write your thoughts here -cfl # # I think @default is fine, leaves most possible flexibility to the user. # Other thoughts? -rn @default def __nonzero__(self): return True @override def __repr__(self): # XXX: is this a relict from plumber prototyping? -rn #if hasattr(self.__class__, '_wrapped'): # class_name = self.__class__._wrapped.__name__ #else: # class_name = self.__class__.__name__ class_name = self.__class__.__name__ # XXX: This is mainly used in doctest, I think # doctest fails if we output utf-8 name = unicode(self.__name__).encode('ascii', 'replace') return "<%s object '%s' at %s>" % (class_name, name, hex( id(self))[:-1]) __str__ = override(__repr__)
class Behavior1(Behavior): K = override('Behavior1') L = finalize('Behavior1')
class Behavior2(Behavior): K = finalize('Behavior2') L = override('Behavior2')
class Behavior1(Behavior): K = default('Behavior1') L = override('Behavior1')
class Behavior2(Behavior): K = override('Behavior2') L = default('Behavior2')
class Behavior1(Behavior): J = default('Behavior1') K = default('Behavior1') M = override('Behavior1')