# Path: lib/python/asterisk/test_runner.py
# def load_and_parse_module(type_name):
#     """Take a qualified module/object name, load the module, and return
#     a typename specifying the object
# 
#     Keyword Arguments:
#     type_name A fully qualified module/object to load into memory
# 
#     Returns:
#     An object type that to be instantiated
#     None on error
#     """
# 
#     LOGGER.debug("Importing %s" % type_name)
# 
#     # Split the object typename into its constituent parts - the module name
#     # and the actual type of the object in that module
#     parts = type_name.split('.')
#     module_name = ".".join(parts[:-1])
# 
#     if not len(module_name):
#         LOGGER.error("No module specified: %s" % typename)
#         return None
# 
#     if os.path.exists('lib/python/asterisk/%s.py' % module_name):
#         # This is convoluted but required.  lib/python/asterisk packages
#         # must be loaded using absolute package names and 'asterisk' must
#         # be included in the list of parts.  We cannot simply prepend
#         # type_name from the start because this blocks load of modules
#         # that are local to the test (add-test-to-search-path: 'True').
#         module_name = 'asterisk.' + module_name
#         parts = ['asterisk'] + parts
# 
#     module = __import__(module_name)
#     for comp in parts[1:]:
#         module = getattr(module, comp)
#     return module
# 
# Path: lib/python/asterisk/pluggable_registry.py
# PLUGGABLE_ACTION_REGISTRY = PluggableRegistry()
# 
# PLUGGABLE_EVENT_REGISTRY = PluggableRegistry()
# 
# class PluggableRegistry(object):
#     """Registry for pluggable modules"""
# 
#     def __init__(self):
#         self.registry = {}
# 
#     def register(self, key, factory):
#         """Register a module"""
#         self.registry[key] = factory
# 
#     def check(self, key):
#         """Check whether a module factory exists for the given key"""
#         if key in self.registry:
#             return True
#         return False
# 
#     def get_class(self, key):
#         """Get the class for a module"""
#         return self.registry[key]


import os
import sys
import logging
import shutil
import re
from .ami import AMIEventInstance
from twisted.internet import reactor
from starpy import fastagi
from .test_runner import load_and_parse_module
from .pluggable_registry import PLUGGABLE_ACTION_REGISTRY,\
    PLUGGABLE_EVENT_REGISTRY,\
    PluggableRegistry
from . import matcher
        self.test_object.set_passed(self.passed)
        return callback_param


class AMIChannelHangup(AMIEventInstance):
    """An AMIEventInstance derived class that hangs up a channel when an
    event is matched."""

    def __init__(self, instance_config, test_object):
        """Constructor for pluggable modules"""
        super(AMIChannelHangup, self).__init__(instance_config, test_object)
        self.hungup_channel = False
        self.delay = instance_config.get('delay') or 0

    def event_callback(self, ami, event):
        """Override of the event callback"""
        if self.hungup_channel:
            return
        if 'channel' not in event:
            return
        LOGGER.info("Hanging up channel %s", event['channel'])
        self.hungup_channel = True
        reactor.callLater(self.delay, ami.hangup, event['channel'])
        return (ami, event)


class AMIChannelHangupAll(AMIEventInstance):
    """An AMIEventInstance derived class that hangs up all the channels when
    an event is matched."""


# Path: lib/python/asterisk/test_runner.py
# def load_and_parse_module(type_name):
#     """Take a qualified module/object name, load the module, and return
#     a typename specifying the object
# 
#     Keyword Arguments:
#     type_name A fully qualified module/object to load into memory
# 
#     Returns:
#     An object type that to be instantiated
#     None on error
#     """
# 
#     LOGGER.debug("Importing %s" % type_name)
# 
#     # Split the object typename into its constituent parts - the module name
#     # and the actual type of the object in that module
#     parts = type_name.split('.')
#     module_name = ".".join(parts[:-1])
# 
#     if not len(module_name):
#         LOGGER.error("No module specified: %s" % typename)
#         return None
# 
#     if os.path.exists('lib/python/asterisk/%s.py' % module_name):
#         # This is convoluted but required.  lib/python/asterisk packages
#         # must be loaded using absolute package names and 'asterisk' must
#         # be included in the list of parts.  We cannot simply prepend
#         # type_name from the start because this blocks load of modules
#         # that are local to the test (add-test-to-search-path: 'True').
#         module_name = 'asterisk.' + module_name
#         parts = ['asterisk'] + parts
# 
#     module = __import__(module_name)
#     for comp in parts[1:]:
#         module = getattr(module, comp)
#     return module
# 
# Path: lib/python/asterisk/pluggable_registry.py
# PLUGGABLE_ACTION_REGISTRY = PluggableRegistry()
# 
# PLUGGABLE_EVENT_REGISTRY = PluggableRegistry()
# 
# class PluggableRegistry(object):
#     """Registry for pluggable modules"""
# 
#     def __init__(self):
#         self.registry = {}
# 
#     def register(self, key, factory):
#         """Register a module"""
#         self.registry[key] = factory
# 
#     def check(self, key):
#         """Check whether a module factory exists for the given key"""
#         if key in self.registry:
#             return True
#         return False
# 
#     def get_class(self, key):
#         """Get the class for a module"""
#         return self.registry[key]


# Path: lib/python/asterisk/pluggable_modules.py
import os
import sys
import logging
import shutil
import re
from .ami import AMIEventInstance
from twisted.internet import reactor
from starpy import fastagi
from .test_runner import load_and_parse_module
from .pluggable_registry import PLUGGABLE_ACTION_REGISTRY,\
    PLUGGABLE_EVENT_REGISTRY,\
    PluggableRegistry
from . import matcher

        self.test_object.set_passed(self.passed)
        return callback_param


class AMIChannelHangup(AMIEventInstance):
    """An AMIEventInstance derived class that hangs up a channel when an
    event is matched."""

    def __init__(self, instance_config, test_object):
        """Constructor for pluggable modules"""
        super(AMIChannelHangup, self).__init__(instance_config, test_object)
        self.hungup_channel = False
        self.delay = instance_config.get('delay') or 0

    def event_callback(self, ami, event):
        """Override of the event callback"""
        if self.hungup_channel:
            return
        if 'channel' not in event:
            return
        LOGGER.info("Hanging up channel %s", event['channel'])
        self.hungup_channel = True
        reactor.callLater(self.delay, ami.hangup, event['channel'])
        return (ami, event)


class AMIChannelHangupAll(AMIEventInstance):
    """An AMIEventInstance derived class that hangs up all the channels when
    an event is matched."""


    def __init__(self, instance_config, test_object):