Source code for nti.site.transient

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Transient, in-memory, non-persistent site and site manager
implementations. These are used to get non-persistent
host-based global IComponents into the base resolution order.

.. $Id$
"""

# turn off warning for not calling superclass, calling indirect superclass and
# accessing protected methods. we're deliberately doing both
# pylint: disable=W0233,W0231,W0212

from __future__ import print_function, unicode_literals, absolute_import, division
__docformat__ = "restructuredtext en"

logger = __import__('logging').getLogger(__name__)

from zope import interface

from zope.component import interfaces as comp_interfaces
from zope.component.persistentregistry import PersistentComponents as _ZPersistentComponents

from zope.container.contained import Contained as _ZContained

from zope.site.site import LocalSiteManager as _ZLocalSiteManager

# TODO: All this site mucking may be expensive. It has significant possibilities
# for optimization (caching) using the fact that much of it is read only.

[docs]class BasedSiteManager(_ZLocalSiteManager): """ A site manager that exists simply to have bases, but not to record itself as children of those bases (since that's unnecessary for our purposes and leads to ZODB conflicts). """ # Note that the adapter registries in the base objects /will/ have # weak references to this object; it's very hard to stop this. These # will stick around until a gc is run. (For testing purposes, # it is important to GC or you can get weird errors like: # File "zope/interface/adapter.py", line 456, in changed # super(AdapterLookupBase, self).changed(None) # File "ZODB/Connection.py", line 857, in setstate # raise ConnectionStateError(msg) # ConfigurationExecutionError: <class 'ZODB.POSException.ConnectionStateError'>: # Shouldn't load state for 0x237f4ee301650a49 when the connection is closed # in: # File "zope/site/configure.zcml", line 13.4-14.71 # <implements interface="zope.annotation.interfaces.IAttributeAnnotatable" /> # Fortunately, CPython's GC is precise and refcounting, so as long as we do not leak # refs to these, we're fine def _setBases(self, bases): # Bypass the direct superclass. _ZPersistentComponents._setBases(self, bases) def __init__(self, site, name, bases): # Bypass the direct superclass to avoid setting # bases multiple times and initing the BTree portion, which we won't use # NOTE: This means we are fairly tightly coupled _ZPersistentComponents.__init__(self) # Locate the site manager self.__parent__ = site self.__name__ = name self.__bases__ = bases def _newContainerData(self): # pragma: no cover return None # We won't be used as a folder def __reduce__(self): raise TypeError("BasedSiteManager should not be pickled") __getstate__ = __reduce__
[docs]class HostSiteManager(BasedSiteManager): # pylint:disable=too-many-ancestors """ A site manager that is intended to be used with globally registered IComponents plus the application persistent components. """ def __init__(self, site, name, host_components, persistent_components): self._host_components = host_components self._persistent_components = persistent_components BasedSiteManager.__init__(self, site, name, (host_components, persistent_components)) @property def host_components(self): return self._host_components @property def persistent_components(self): return self._persistent_components
[docs]@interface.implementer(comp_interfaces.ISite) class TrivialSite(_ZContained): """ Trivial non-persistent implementation of :class:`.ISite` """ def __init__(self, site_manager): self._sm = site_manager
[docs] def getSiteManager(self): return self._sm
def __reduce__(self): raise TypeError("TrivialSite should not be pickled")