.. -*-doctest-*-

==============================
Broken Component Registrations
==============================

Start with a ZODB root with a persistent component registry in it.

    >>> from ZODB.DemoStorage import DemoStorage
    >>> from ZODB.DB import DB
    >>> storage = DemoStorage()
    >>> db = DB(storage)

    >>> from zope.component import persistentregistry
    >>> db.open().root()['registry'] = registry_one = (
    ...     persistentregistry.PersistentComponents())

Register a persistent component and non-persistent component to the
registry.

    >>> from experimental.broken import tests
    >>> foo = tests.Foo()
    >>> registry_one.registerUtility(component=foo, provided=tests.IFoo)
    >>> registry_one.registerAdapter(
    ...     factory=foo, required=(tests.IFoo,), provided=tests.IFoo)
    >>> registry_one.registerSubscriptionAdapter(
    ...     factory=foo, required=(tests.IFoo,), provided=tests.IFoo)
    >>> registry_one.registerHandler(
    ...     factory=foo, required=(tests.IFoo,))

    >>> bar = tests.Bar()
    >>> registry_one.registerUtility(component=bar, provided=tests.IQux)
    >>> registry_one.registerAdapter(
    ...     factory=bar, required=(tests.IQux,), provided=tests.IQux)
    >>> registry_one.registerSubscriptionAdapter(
    ...     factory=bar, required=(tests.IQux,), provided=tests.IQux)
    >>> registry_one.registerHandler(
    ...     factory=bar, required=(tests.IQux,))

    >>> import transaction
    >>> transaction.commit()

When the code for some registrations has been removed, the registry is
broken.

    >>> del tests.IFoo
    >>> del tests.IQux
    >>> del tests.Foo
    >>> del tests.Bar
    >>> tests.reset()

    >>> registry_two = db.open().root()['registry']
    >>> sorted(registry_two.registeredUtilities())
    [UtilityRegistration(<PersistentComponents >, IFoo, u'',
      broken object, None, u''),
     UtilityRegistration(<PersistentComponents >, IQux, u'',
      broken object, None, u'')]
    >>> sorted(registry_two.registeredAdapters())
    [AdapterRegistration(<PersistentComponents >, [IFoo], IFoo, u'',
      broken object, u''),
     AdapterRegistration(<PersistentComponents >, [IQux], IQux, u'',
      broken object, u'')]
    >>> sorted(registry_two.registeredSubscriptionAdapters())
    [SubscriptionRegistration(<PersistentComponents >, [IFoo], IFoo, u'',
      broken object, u''),
     SubscriptionRegistration(<PersistentComponents >, [IQux], IQux, u'',
      broken object, u'')]
    >>> sorted(registry_two.registeredHandlers())
    [HandlerRegistration(<PersistentComponents >, [IFoo], u'',
      broken object, u''),
     HandlerRegistration(<PersistentComponents >, [IQux], u'',
      broken object, u'')]

    >>> registry_two.queryUtility(tests.IBar)
    Traceback (most recent call last):
    AttributeError: type object 'I...' has no attribute '__iro__'
    >>> registry_two.queryAdapter(None, tests.IBar)
    Traceback (most recent call last):
    AttributeError: type object 'I...' has no attribute '__iro__'
    >>> registry_two.queryMultiAdapter([None], tests.IBar)
    Traceback (most recent call last):
    AttributeError: type object 'I...' has no attribute '__iro__'
    >>> registry_two.subscribers([None], tests.IBar)
    Traceback (most recent call last):
    AttributeError: type object 'I...' has no attribute '__iro__'
    >>> registry_two.handle([None])
    Traceback (most recent call last):
    AttributeError: type object 'I...' has no attribute '__iro__'

When the patches are applied, the component registry is once again
functional.

    >>> from zope.interface.interface import InterfaceClass
    >>> from zope.component import persistentregistry
    >>> from experimental.broken import registry
    >>> from experimental.broken import interface
    >>> InterfaceClass.__reduce__ = interface.interface_reduce
    >>> persistentregistry.PersistentAdapterRegistry.__setstate__ = (
    ...     registry.registry_setstate)
    >>> persistentregistry.PersistentComponents.__setstate__ = (
    ...     registry.components_setstate)

    >>> registry_two = db.open().root()['registry']
    >>> sorted(registry_two.registeredUtilities())
    [UtilityRegistration(<PersistentComponents >, IFoo, u'',
      broken object, None, u''),
     UtilityRegistration(<PersistentComponents >, IQux, u'',
      broken object, None, u'')]
    >>> sorted(registry_two.registeredAdapters())
    [AdapterRegistration(<PersistentComponents >, [IFoo], IFoo, u'',
      broken object, u''),
     AdapterRegistration(<PersistentComponents >, [IQux], IQux, u'',
      broken object, u'')]
    >>> sorted(registry_two.registeredSubscriptionAdapters())
    [SubscriptionRegistration(<PersistentComponents >, [IFoo], IFoo, u'',
      broken object, u''),
     SubscriptionRegistration(<PersistentComponents >, [IQux], IQux, u'',
      broken object, u'')]
    >>> sorted(registry_two.registeredHandlers())
    [HandlerRegistration(<PersistentComponents >, [IFoo], u'',
      broken object, u''),
     HandlerRegistration(<PersistentComponents >, [IQux], u'',
      broken object, u'')]

    >>> registry_two.queryUtility(tests.IBar)
    >>> registry_two.queryAdapter(None, tests.IBar)
    >>> registry_two.queryMultiAdapter([None], tests.IBar)
    >>> registry_two.subscribers([None], tests.IBar)
    []
    >>> registry_two.handle([None])

Registrations can be removed when the classes and/or interfaces are
missing.

    >>> foo_reg, bar_reg = sorted(registry_two.registeredAdapters())
    >>> registry_two.unregisterUtility(provided=foo_reg.provided)
    True
    >>> registry_two.unregisterAdapter(
    ...     required=foo_reg.required, provided=foo_reg.provided)
    True

    >>> foo_reg, bar_reg = sorted(
    ...     registry_two.registeredSubscriptionAdapters())
    >>> registry_two.unregisterSubscriptionAdapter(
    ...     required=foo_reg.required, provided=foo_reg.provided)
    True
    >>> registry_two.unregisterHandler(required=foo_reg.required)
    True

The component registry can be committed to the ZODB when it has been
changed and still contains broken registrations.

    >>> transaction.commit()

The remaining broken registrations still work.

    >>> registry_three = db.open().root()['registry']
    >>> sorted(registry_three.registeredUtilities())
    [UtilityRegistration(<PersistentComponents >, IQux, u'',
      broken object, None, u'')]
    >>> sorted(registry_three.registeredAdapters())
    [AdapterRegistration(<PersistentComponents >, [IQux], IQux, u'',
      broken object, u'')]
    >>> sorted(registry_three.registeredSubscriptionAdapters())
    [SubscriptionRegistration(<PersistentComponents >, [IQux], IQux, u'',
      broken object, u'')]
    >>> sorted(registry_three.registeredHandlers())
    [HandlerRegistration(<PersistentComponents >, [IQux], u'',
      broken object, u'')]

    >>> registry_three.queryUtility(tests.IBar)
    >>> registry_three.queryAdapter(None, tests.IBar)
    >>> registry_three.queryMultiAdapter([None], tests.IBar)
    >>> registry_three.subscribers([None], tests.IBar)
    []
    >>> registry_three.handle([None])

When the code has been restored the component registry behaves as normal.

    >>> tests.tearDown()

    >>> registry_four = db.open().root()['registry']
    >>> sorted(registry_four.registeredUtilities())
    [UtilityRegistration(<PersistentComponents >, IQux, u'',
      <experimental.broken.tests.Bar object at 0x...>, None, u'')]
    >>> sorted(registry_four.registeredAdapters())
    [AdapterRegistration(<PersistentComponents >, [IQux], IQux, u'',
      <experimental.broken.tests.Bar object at 0x...>, u'')]
    >>> sorted(registry_four.registeredSubscriptionAdapters())
    [SubscriptionRegistration(<PersistentComponents >, [IQux], IQux, u'',
      <experimental.broken.tests.Bar object at 0x...>, u'')]
    >>> sorted(registry_four.registeredHandlers())
    [HandlerRegistration(<PersistentComponents >, [IQux], u'',
      <experimental.broken.tests.Bar object at 0x...>, u'')]

    >>> registry_four.queryUtility(tests.IBar)
    >>> registry_four.queryAdapter(None, tests.IBar)
    >>> registry_four.queryMultiAdapter([None], tests.IBar)
    >>> registry_four.subscribers([None], tests.IBar)
    []
    >>> registry_four.handle([None])

Remove the last registrations.

    >>> registry_five = db.open().root()['registry']
    >>> bar_reg, = sorted(registry_five.registeredAdapters())

    >>> registry_five.unregisterUtility(provided=tests.IQux)
    True
    >>> registry_five.unregisterAdapter(
    ...     required=(tests.IQux,), provided=tests.IQux)
    True
    >>> registry_five.unregisterSubscriptionAdapter(
    ...     required=(tests.IQux,), provided=tests.IQux)
    True
    >>> registry_five.unregisterHandler(required=(tests.IQux,))
    True

    >>> sorted(registry_five.registeredUtilities())
    []
    >>> sorted(registry_five.registeredAdapters())
    []
    >>> sorted(registry_five.registeredSubscriptionAdapters())
    []
    >>> sorted(registry_five.registeredHandlers())
    []

    >>> registry_five.queryUtility(tests.IBar)
    >>> registry_five.queryAdapter(None, tests.IBar)
    >>> registry_five.queryMultiAdapter([None], tests.IBar)
    >>> registry_five.subscribers([None], tests.IBar)
    []
    >>> registry_five.handle([None])
