Source code for pyams_utils.container

#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
# pylint: disable=no-name-in-module

"""PyAMS_utils.container module

This module provides several classes, adapters and functions about containers.
"""

from BTrees.OOBTree import OOBTree
from persistent.list import PersistentList
from pyramid.threadlocal import get_current_registry
from zope.container.interfaces import IContained, IContainer
from zope.container.ordered import OrderedContainer
from zope.lifecycleevent.interfaces import IObjectMovedEvent
from zope.location.interfaces import ISublocations

from pyams_utils.adapter import ContextAdapter, adapter_config


__docformat__ = 'restructuredtext'


[docs]class BTreeOrderedContainer(OrderedContainer): """BTree based ordered container This container maintain a manual order of it's contents """ def __init__(self): # pylint: disable=super-init-not-called self._data = OOBTree() self._order = PersistentList()
[docs]class ParentSelector: """Interface based parent selector This selector can be used as a subscriber predicate on IObjectAddedEvent to define an interface that the new parent must support for the event to be applied:: .. code-block:: python from pyams_utils.interfaces.site import ISiteRoot @subscriber(IObjectAddedEvent, parent_selector=ISiteRoot) def siteroot_object_added_event_handler(event): '''This is an event handler for an ISiteRoot object added event''' """ def __init__(self, ifaces, config): # pylint: disable=unused-argument if not isinstance(ifaces, (list, tuple, set)): ifaces = (ifaces,) self.interfaces = ifaces
[docs] def text(self): """Predicate string output""" return 'parent_selector = %s' % str(self.interfaces)
phash = text def __call__(self, event): if not IObjectMovedEvent.providedBy(event): return False for intf in self.interfaces: try: if intf.providedBy(event.newParent): return True except (AttributeError, TypeError): if isinstance(event.newParent, intf): return True return False
[docs]@adapter_config(context=IContained, provides=ISublocations) class ContainerSublocationsAdapter(ContextAdapter): """Contained object sub-locations adapter This adapter checks for custom ISublocations interface adapters which can be defined by any component to get access to inner locations, defined for example via annotations. """
[docs] def sublocations(self): """See `zope.location.interfaces.ISublocations` interface""" context = self.context # Check for adapted sub-locations first... registry = get_current_registry() for name, adapter in registry.getAdapters((context,), ISublocations): if not name: # don't reuse default adapter!! continue yield from adapter.sublocations() # then yield container items if IContainer.providedBy(context): yield from context.values()
[docs]def find_objects_matching(root, condition, ignore_root=False): """Find all objects in root that match the condition The condition is a Python callable object that takes an object as argument and must return a boolean result. All sub-objects of the root will also be searched recursively. :param object root: the parent object from which search is started :param callable condition: a callable object which may return true for a given object to be selected :param boolean ignore_root: if *True*, the root object will not be returned, even if it matches the given condition :return: an iterator for all root's sub-objects matching condition """ if (not ignore_root) and condition(root): yield root locations = ISublocations(root, None) if locations is not None: for location in locations.sublocations(): # pylint: disable=too-many-function-args if condition(location): yield location yield from find_objects_matching(location, condition, ignore_root=True)
[docs]def find_objects_providing(root, interface): """Find all objects in root that provide the specified interface All sub-objects of the root will also be searched recursively. :param object root: object; the parent object from which search is started :param Interface interface: interface; an interface that sub-objects should provide :return: an iterator for all root's sub-objects that provide the given interface """ yield from find_objects_matching(root, interface.providedBy)