def hookable(cls):
    """
    Initialise hookery in a class that declares hooks by decorating it with this decorator.

    This replaces the class with another one which has the same name, but also inherits Hookable
    which has HookableMeta set as metaclass so that sub-classes of cls will have hook descriptors
    initialised properly.

    When you say:
        @hookable
        class My:
            before = Hook()

    then @hookable changes My.before to be a HookDescriptor which is then
    changed into Hook if anyone accesses it.

    There is no need to decorate sub-classes of cls with @hookable.
    """
    assert isinstance(cls, type)

    # For classes that won't have descriptors initialised by metaclass, need to do it here.
    hook_definitions = []
    if not issubclass(cls, Hookable):
        for k, v in list(cls.__dict__.items()):
            if isinstance(v, (ClassHook, InstanceHook)):
                delattr(cls, k)
                if v.name is None:
                    v.name = k
                hook_definitions.append((k, v))

    hookable_cls = type(cls.__name__, (cls, Hookable), {})

    for k, v in hook_definitions:
        setattr(hookable_cls, k, HookDescriptor(defining_hook=v, defining_class=hookable_cls))

    return hookable_cls
Initialise hookery in a class that declares hooks by decorating it with this decorator.

    This replaces the class with another one which has the same name, but also inherits Hookable
    which has HookableMeta set as metaclass so that sub-classes of cls will have hook descriptors
    initialised properly.

    When you say:
        @hookable
        class My:
            before = Hook()

    then @hookable changes My.before to be a HookDescriptor which is then
    changed into Hook if anyone accesses it.

    There is no need to decorate sub-classes of cls with @hookable.