@on_trait_change('_providers:extension_point_changed')
    def _providers_extension_point_changed(self, obj, trait_name, old, event):

        logger.debug('provider <%s> extension point changed', obj)

        extension_point_id = event.extension_point_id

        # If the extension point has not yet been accessed then we don't fire a
        # changed event.
        #
        # This is because we only access extension points lazily and so we
        # can't tell what has actually changed because we have nothing to
        # compare it to!
        if not extension_point_id in self._extensions:
            return

        # This is a list of lists where each inner list contains the
        # contributions made to the extension point by a single provider.
        #
        # fixme: This causes a problem if the extension point has not yet been
        # accessed! The tricky thing is that if it hasn't been accessed yet
        # how do we know what has changed?!? Maybe we should just return an
        # empty list instead of barfing!
        extensions = self._extensions[extension_point_id]

        # Find the index of the provider in the provider list. Its
        # contributions are at the same index in the extensions list of lists.
        provider_index = self._providers.index(obj)

        # Get the updated list from the provider.
        extensions[provider_index] = obj.get_extensions(extension_point_id)

        # Find where the provider's contributions are in the whole 'list'.
        offset = sum(map(len, extensions[:provider_index]))

        # Translate the event index from one that refers to the list of
        # contributions from the provider, to the list of contributions from
        # all providers.
        index = self._translate_index(event.index, offset)

        # Find out who is listening.
        refs = self._get_listener_refs(extension_point_id)

        # Let any listeners know that the extensions have been added.
        self._call_listeners(
            refs, extension_point_id, event.added, event.removed, index
        )

        return

    #### Methods ##############################################################
Dynamic trait change handler.
dataset/ETHPy150Open enthought/envisage/envisage/provider_extension_registry.py/ProviderExtensionRegistry._providers_extension_point_changed