##############################################################################
#
# Copyright (c) 2004 Zope Foundation and Contributors.
# 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.
#
##############################################################################
"""Utility functions for evolving database generations.
"""
[docs]def findObjectsMatching(root, condition):
"""Find all objects in the root that match the condition.
The condition is a callable Python object that takes an object as an
argument and must return `True` or `False`.
All sub-objects of the root will also be searched recursively. All mapping
objects providing ``values()`` are supported.
Example:
>>> class A(dict):
... def __init__(self, name):
... self.name = name
>>> class B(dict):
... def __init__(self, name):
... self.name = name
>>> class C(dict):
... def __init__(self, name):
... self.name = name
>>> tree = A('a1')
>>> tree['b1'] = B('b1')
>>> tree['c1'] = C('c1')
>>> tree['b1']['a2'] = A('a2')
>>> tree['b1']['b2'] = B('b2')
>>> tree['b1']['b2']['c2'] = C('c2')
>>> tree['b1']['b2']['a3'] = A('a3')
Find all instances of class A:
>>> matches = findObjectsMatching(tree, lambda x: isinstance(x, A))
>>> names = [x.name for x in matches]
>>> names.sort()
>>> names
['a1', 'a2', 'a3']
Find all objects having a '2' in the name:
>>> matches = findObjectsMatching(tree, lambda x: '2' in x.name)
>>> names = [x.name for x in matches]
>>> names.sort()
>>> names
['a2', 'b2', 'c2']
If there is no ``values`` on the root, we stop:
>>> root = [1, 2, 3]
>>> found = list(findObjectsMatching(root, lambda x: True))
>>> found == [root]
True
"""
if condition(root):
yield root
if hasattr(root, 'values'):
for subobj in root.values():
yield from findObjectsMatching(subobj, condition)
[docs]def findObjectsProviding(root, interface):
"""Find all objects in the root that provide the specified interface.
All sub-objects of the root will also be searched recursively.
Example:
>>> from zope.interface import Interface, implementer
>>> class IA(Interface):
... pass
>>> class IB(Interface):
... pass
>>> class IC(IA):
... pass
>>> @implementer(IA)
... class A(dict):
... def __init__(self, name):
... self.name = name
>>> @implementer(IB)
... class B(dict):
... def __init__(self, name):
... self.name = name
>>> @implementer(IC)
... class C(dict):
... def __init__(self, name):
... self.name = name
>>> tree = A('a1')
>>> tree['b1'] = B('b1')
>>> tree['c1'] = C('c1')
>>> tree['b1']['a2'] = A('a2')
>>> tree['b1']['b2'] = B('b2')
>>> tree['b1']['b2']['c2'] = C('c2')
>>> tree['b1']['b2']['a3'] = A('a3')
Find all objects that provide IB:
>>> matches = findObjectsProviding(tree, IB)
>>> names = [x.name for x in matches]
>>> names.sort()
>>> names
['b1', 'b2']
Find all objects that provide IA:
>>> matches = findObjectsProviding(tree, IA)
>>> names = [x.name for x in matches]
>>> names.sort()
>>> names
['a1', 'a2', 'a3', 'c1', 'c2']
"""
yield from findObjectsMatching(root, interface.providedBy)
try:
import zope.app.publication.zopepublication
except ImportError:
# 'Application' is what ZopePublication uses, up through at least
# 4.3.1
#: The name of the root folder.
#: If ``zope.app.publication.zopepublication`` is available,
#: this is imported from there.
ROOT_NAME = 'Application'
else: # pragma: no cover
#: The name of the root folder.
#: If ``zope.app.publication.zopepublication`` is available,
#: this is imported from there.
ROOT_NAME = zope.app.publication.zopepublication.ZopePublication.root_name
[docs]def getRootFolder(context):
"""Get the root folder of the ZODB.
We need some set up. Create a database:
>>> from ZODB.MappingStorage import DB
>>> from zope.generations.generations import Context
>>> import transaction
>>> db = DB()
>>> context = Context()
>>> tx = transaction.begin()
>>> context.connection = db.open()
>>> root = context.connection.root()
Add a root folder:
>>> from zope.site.folder import rootFolder
>>> root[ROOT_NAME] = rootFolder()
>>> tx.commit()
>>> tx = transaction.begin()
Now we can get the root folder using the function:
>>> getRootFolder(context) # doctest: +ELLIPSIS
<zope.site.folder.Folder object at ...>
We'd better clean up:
>>> tx.abort()
>>> context.connection.close()
>>> db.close()
"""
return context.connection.root().get(ROOT_NAME, None)