# Path: doubles/exceptions.py
# class VerifyingDoubleImportError(AssertionError):
#     """
#     An exception raised when attempting to create a verifying double from an invalid module path.
#     """
# 
# Path: doubles/object_double.py
# class ObjectDouble(object):
#     """
#     A pure double representing the target object.
# 
#     ::
# 
#         dummy_user = ObjectDouble(user)
# 
#     :param object target: The object the newly created ObjectDouble will verify against.
#     """
#     is_class = False
# 
#     def __init__(self, target):
#         self._doubles_target = target
# 
#     def __repr__(self):
#         """Provides a string representation of the double.
# 
#         NOTE: Includes the memory address and the name of the object being doubled.
# 
#         :return: A string representation of the double.
#         :rtype: str
#         """
# 
#         address = hex(id(self))
#         class_name = self.__class__.__name__
# 
#         return '<{} of {!r} object at {}>'.format(
#             class_name,
#             self._doubles_target,
#             address
#         )
# 
# Path: doubles/utils.py
# def get_module(module_path, full_path):
#     """Return the module given its path.
# 
#     :param str module_path: The path to the module to import.
#     :param str full_path: The full path to the class that will be doubled.
#     :return: The module object.
#     :rtype: module
#     :raise: ``VerifyingDoubleImportError`` if the module can't be imported.
#     """
# 
#     try:
#         return import_module(module_path)
#     except ImportError:
#         raise VerifyingDoubleImportError('Cannot import object from path: {}.'.format(full_path))
# 
# def get_path_components(path):
#     """Extract the module name and class name out of the fully qualified path to the class.
# 
#     :param str path: The full path to the class.
#     :return: The module path and the class name.
#     :rtype: str, str
#     :raise: ``VerifyingDoubleImportError`` if the path is to a top-level module.
#     """
# 
#     path_segments = path.split('.')
#     module_path = '.'.join(path_segments[:-1])
# 
#     if module_path == '':
#         raise VerifyingDoubleImportError('Invalid import path: {}.'.format(path))
# 
#     class_name = path_segments[-1]
# 
#     return module_path, class_name


from inspect import isclass
from doubles.exceptions import VerifyingDoubleImportError
from doubles.object_double import ObjectDouble
from doubles.utils import get_module, get_path_components


def _get_doubles_target(module, class_name, path):
    """Validate and return the class to be doubled.

    :param module module: The module that contains the class that will be doubled.
    :param str class_name: The name of the class that will be doubled.
    :param str path: The full path to the class that will be doubled.
    :return: The class that will be doubled.
    :rtype: type
    :raise: ``VerifyingDoubleImportError`` if the target object doesn't exist or isn't a class.
    """

    try:
        doubles_target = getattr(module, class_name)
        if isinstance(doubles_target, ObjectDouble):
            return doubles_target._doubles_target

        if not isclass(doubles_target):
            raise VerifyingDoubleImportError(
                'Path does not point to a class: {}.'.format(path)
            )

        return doubles_target
    except AttributeError:
        raise VerifyingDoubleImportError(
            'No object at path: {}.'.format(path)
        )



# Path: doubles/exceptions.py
# class VerifyingDoubleImportError(AssertionError):
#     """
#     An exception raised when attempting to create a verifying double from an invalid module path.
#     """
# 
# Path: doubles/object_double.py
# class ObjectDouble(object):
#     """
#     A pure double representing the target object.
# 
#     ::
# 
#         dummy_user = ObjectDouble(user)
# 
#     :param object target: The object the newly created ObjectDouble will verify against.
#     """
#     is_class = False
# 
#     def __init__(self, target):
#         self._doubles_target = target
# 
#     def __repr__(self):
#         """Provides a string representation of the double.
# 
#         NOTE: Includes the memory address and the name of the object being doubled.
# 
#         :return: A string representation of the double.
#         :rtype: str
#         """
# 
#         address = hex(id(self))
#         class_name = self.__class__.__name__
# 
#         return '<{} of {!r} object at {}>'.format(
#             class_name,
#             self._doubles_target,
#             address
#         )
# 
# Path: doubles/utils.py
# def get_module(module_path, full_path):
#     """Return the module given its path.
# 
#     :param str module_path: The path to the module to import.
#     :param str full_path: The full path to the class that will be doubled.
#     :return: The module object.
#     :rtype: module
#     :raise: ``VerifyingDoubleImportError`` if the module can't be imported.
#     """
# 
#     try:
#         return import_module(module_path)
#     except ImportError:
#         raise VerifyingDoubleImportError('Cannot import object from path: {}.'.format(full_path))
# 
# def get_path_components(path):
#     """Extract the module name and class name out of the fully qualified path to the class.
# 
#     :param str path: The full path to the class.
#     :return: The module path and the class name.
#     :rtype: str, str
#     :raise: ``VerifyingDoubleImportError`` if the path is to a top-level module.
#     """
# 
#     path_segments = path.split('.')
#     module_path = '.'.join(path_segments[:-1])
# 
#     if module_path == '':
#         raise VerifyingDoubleImportError('Invalid import path: {}.'.format(path))
# 
#     class_name = path_segments[-1]
# 
#     return module_path, class_name


# Path: doubles/instance_double.py
from inspect import isclass
from doubles.exceptions import VerifyingDoubleImportError
from doubles.object_double import ObjectDouble
from doubles.utils import get_module, get_path_components



def _get_doubles_target(module, class_name, path):
    """Validate and return the class to be doubled.

    :param module module: The module that contains the class that will be doubled.
    :param str class_name: The name of the class that will be doubled.
    :param str path: The full path to the class that will be doubled.
    :return: The class that will be doubled.
    :rtype: type
    :raise: ``VerifyingDoubleImportError`` if the target object doesn't exist or isn't a class.
    """

    try:
        doubles_target = getattr(module, class_name)
        if isinstance(doubles_target, ObjectDouble):
            return doubles_target._doubles_target

        if not isclass(doubles_target):
            raise VerifyingDoubleImportError(
                'Path does not point to a class: {}.'.format(path)
            )

        return doubles_target
    except AttributeError:
        raise VerifyingDoubleImportError(
            'No object at path: {}.'.format(path)
        )



class InstanceDouble(ObjectDouble):