# Path: cis/data_io/products/AProduct.py
# def get_data(filenames, variable, product=None):
#     """
#     Top level routine for calling the correct product's :meth:`create_data_object` routine.
# 
#     :param list filenames: A list of filenames to read data from
#     :param str variable: The variable to create the :class:`.CommonData` object from
#     :param str product: The product to read data with - this should be a string which matches the name of one of the
#      subclasses of :class:`.AProduct`. If none is supplied it is guessed from the filename signature.
#     :return: A :class:`.CommonData` variable
#     """
#     product_cls = __get_class(filenames[0], product)
# 
#     logging.info("Retrieving data using product " + product_cls.__name__ + "...")
#     try:
#         data = product_cls().create_data_object(filenames, variable)
#         return data
#     except Exception as e:
#         logging.debug("Error in product plugin %s:\n%s" % (product_cls.__name__, traceback.format_exc()))
#         raise ProductPluginException("An error occurred retrieving data using the product %s. Check that this "
#                                      "is the correct product plugin for your chosen data. Exception was %s: %s."
#                                      % (product_cls.__name__, type(e).__name__, e.args[0]), e)
# 
# def __get_class(filename, product=None):
#     """
#     Identify the subclass of :class:`.AProduct` to a given product name if specified.
#     If the product name is not specified, the routine uses the signature (regex)
#     given by :meth:`get_file_signature` to infer the product class from the filename.
# 
#     Note, only the first filename of the list is use here.
# 
#     :param filename: A single filename
#     :param product: name of the product
#     :return: a subclass of :class:`.AProduct`
#     """
#     import re
#     import os
#     import cis.plugin as plugin
#     from cis.exceptions import ClassNotFoundError
# 
#     # Ensure the filename doesn't include the path
#     basename = os.path.basename(filename)
# 
#     product_classes = plugin.find_plugin_classes(AProduct, 'cis.data_io.products')
#     product_classes = sorted(product_classes, key=lambda cls: cls.priority, reverse=True)
# 
#     for cls in product_classes:
# 
#         if product is None:
#             # search for a pattern that matches file signature
#             class_instance = cls()
#             patterns = class_instance.get_file_signature()
#             for pattern in patterns:
#                 # Match the pattern - re.I allows for case insensitive matches.
#                 # Appending '$' to the pattern ensures we match the whole string
#                 if re.match(pattern+'$', basename, re.I) is not None:
#                     logging.debug("Found product class " + cls.__name__ + " matching regex pattern " + pattern)
#                     errors = class_instance.get_file_type_error(filename)
#                     if errors is None:
#                         return cls
#                     else:
#                         logging.info("Product class {} is not right because {}".format(cls.__name__, errors))
#         else:
#             # product specified directly
#             if product == cls.__name__:
#                 logging.debug("Selected product class " + cls.__name__)
#                 return cls
#     error_message = "Product cannot be found for given file.\nSupported products and signatures are:\n"
#     for cls in product_classes:
#         error_message += cls().__class__.__name__ + ": " + str(cls().get_file_signature()) + "\n"
#     raise ClassNotFoundError(error_message)
# 
# def get_coordinates(filenames, product=None):
#     """
#     Top level routine for calling the correct product's :meth:`create_coords` routine.
# 
#     :param list filenames: A list of filenames to read data from
#     :param str product: The product to read data with - this should be a string which matches the name of one of the
#      subclasses of AProduct
#     :return: A :class:`CoordList` object
#     """
#     product_cls = __get_class(filenames[0], product)
# 
#     logging.info("Retrieving coordinates using product " + product_cls.__name__)
#     try:
#         coord = product_cls().create_coords(filenames)
#         return coord
#     except Exception as e:
#         logging.debug("Error in product plugin %s:\n%s" % (product_cls.__name__, traceback.format_exc()))
#         raise ProductPluginException("An error occurred retrieving coordinates using the product %s. Check that this "
#                                      "is the correct product plugin for your chosen data. Exception was %s: %s."
#                                      % (product_cls.__name__, type(e).__name__, e.args[0]), e)
# 
# Path: cis/exceptions.py
# class ClassNotFoundError(CISError):
#     pass


from unittest import TestCase
from hamcrest import *
from nose.tools import eq_, raises
from cis.test.integration_test_data import *
from cis.data_io.products.AProduct import get_data, __get_class as _get_class, get_coordinates
from cis.exceptions import ClassNotFoundError
        from cis.data_io.products.AProduct import AProduct
        from cis.data_io.products.AProduct import AProduct
        from cis import __version__
        from cis.data_io.products.AProduct import get_product_full_name
        from cis.data_io.products import CloudSat
"""
Module to test the abstract AProduct class and it's helper methods
"""




class TestAProduct(TestCase):

    def test_that_get_data_accepts_valid_product(self):
        _get_class(valid_cloudsat_RVOD_file, product='CloudSat')

    def test_automatic_detection_of_product_for_existing_product(self):
        product_cls = _get_class(valid_cloudsat_RVOD_file)
        eq_(product_cls.__name__, 'CloudSat')

        product_cls = _get_class(valid_caliop_l2_filename)
        eq_(product_cls.__name__, 'Caliop_L2')

    @raises(ClassNotFoundError)
    def test_that_get_class_raises_ClassNotFoundError_for_non_existing_product(self):

# Path: cis/data_io/products/AProduct.py
# def get_data(filenames, variable, product=None):
#     """
#     Top level routine for calling the correct product's :meth:`create_data_object` routine.
# 
#     :param list filenames: A list of filenames to read data from
#     :param str variable: The variable to create the :class:`.CommonData` object from
#     :param str product: The product to read data with - this should be a string which matches the name of one of the
#      subclasses of :class:`.AProduct`. If none is supplied it is guessed from the filename signature.
#     :return: A :class:`.CommonData` variable
#     """
#     product_cls = __get_class(filenames[0], product)
# 
#     logging.info("Retrieving data using product " + product_cls.__name__ + "...")
#     try:
#         data = product_cls().create_data_object(filenames, variable)
#         return data
#     except Exception as e:
#         logging.debug("Error in product plugin %s:\n%s" % (product_cls.__name__, traceback.format_exc()))
#         raise ProductPluginException("An error occurred retrieving data using the product %s. Check that this "
#                                      "is the correct product plugin for your chosen data. Exception was %s: %s."
#                                      % (product_cls.__name__, type(e).__name__, e.args[0]), e)
# 
# def __get_class(filename, product=None):
#     """
#     Identify the subclass of :class:`.AProduct` to a given product name if specified.
#     If the product name is not specified, the routine uses the signature (regex)
#     given by :meth:`get_file_signature` to infer the product class from the filename.
# 
#     Note, only the first filename of the list is use here.
# 
#     :param filename: A single filename
#     :param product: name of the product
#     :return: a subclass of :class:`.AProduct`
#     """
#     import re
#     import os
#     import cis.plugin as plugin
#     from cis.exceptions import ClassNotFoundError
# 
#     # Ensure the filename doesn't include the path
#     basename = os.path.basename(filename)
# 
#     product_classes = plugin.find_plugin_classes(AProduct, 'cis.data_io.products')
#     product_classes = sorted(product_classes, key=lambda cls: cls.priority, reverse=True)
# 
#     for cls in product_classes:
# 
#         if product is None:
#             # search for a pattern that matches file signature
#             class_instance = cls()
#             patterns = class_instance.get_file_signature()
#             for pattern in patterns:
#                 # Match the pattern - re.I allows for case insensitive matches.
#                 # Appending '$' to the pattern ensures we match the whole string
#                 if re.match(pattern+'$', basename, re.I) is not None:
#                     logging.debug("Found product class " + cls.__name__ + " matching regex pattern " + pattern)
#                     errors = class_instance.get_file_type_error(filename)
#                     if errors is None:
#                         return cls
#                     else:
#                         logging.info("Product class {} is not right because {}".format(cls.__name__, errors))
#         else:
#             # product specified directly
#             if product == cls.__name__:
#                 logging.debug("Selected product class " + cls.__name__)
#                 return cls
#     error_message = "Product cannot be found for given file.\nSupported products and signatures are:\n"
#     for cls in product_classes:
#         error_message += cls().__class__.__name__ + ": " + str(cls().get_file_signature()) + "\n"
#     raise ClassNotFoundError(error_message)
# 
# def get_coordinates(filenames, product=None):
#     """
#     Top level routine for calling the correct product's :meth:`create_coords` routine.
# 
#     :param list filenames: A list of filenames to read data from
#     :param str product: The product to read data with - this should be a string which matches the name of one of the
#      subclasses of AProduct
#     :return: A :class:`CoordList` object
#     """
#     product_cls = __get_class(filenames[0], product)
# 
#     logging.info("Retrieving coordinates using product " + product_cls.__name__)
#     try:
#         coord = product_cls().create_coords(filenames)
#         return coord
#     except Exception as e:
#         logging.debug("Error in product plugin %s:\n%s" % (product_cls.__name__, traceback.format_exc()))
#         raise ProductPluginException("An error occurred retrieving coordinates using the product %s. Check that this "
#                                      "is the correct product plugin for your chosen data. Exception was %s: %s."
#                                      % (product_cls.__name__, type(e).__name__, e.args[0]), e)
# 
# Path: cis/exceptions.py
# class ClassNotFoundError(CISError):
#     pass


# Path: cis/test/integration/test_io/test_products/test_Aproduct.py
from unittest import TestCase
from hamcrest import *
from nose.tools import eq_, raises
from cis.test.integration_test_data import *
from cis.data_io.products.AProduct import get_data, __get_class as _get_class, get_coordinates
from cis.exceptions import ClassNotFoundError
        from cis.data_io.products.AProduct import AProduct
        from cis.data_io.products.AProduct import AProduct
        from cis import __version__
        from cis.data_io.products.AProduct import get_product_full_name
        from cis.data_io.products import CloudSat

"""
Module to test the abstract AProduct class and it's helper methods
"""




class TestAProduct(TestCase):

    def test_that_get_data_accepts_valid_product(self):
        _get_class(valid_cloudsat_RVOD_file, product='CloudSat')

    def test_automatic_detection_of_product_for_existing_product(self):
        product_cls = _get_class(valid_cloudsat_RVOD_file)
        eq_(product_cls.__name__, 'CloudSat')

        product_cls = _get_class(valid_caliop_l2_filename)
        eq_(product_cls.__name__, 'Caliop_L2')

    @raises(ClassNotFoundError)
    def test_that_get_class_raises_ClassNotFoundError_for_non_existing_product(self):

        product_cls = _get_class('some_file_that_does_not_match_anything')