Esempio n. 1
0
def _check_class_types_duplicates(class_types, classes):
    """Check duplicated types for input list of class types."""
    duplicates = find_duplicates(class_types)
    if len(duplicates) != 0:  # Return the list of classes with duplicate type
        duplicates_classes = [
            (class_tuple[0], get_private(class_tuple[1], 'class_type'))
            for class_tuple in classes if
            get_private(class_tuple[1], 'class_type', None) in duplicates]
        raise ValueError("following classes have the same class type. Fix "
                         "before continue. {:}".format(duplicates_classes))
Esempio n. 2
0
    def get_class_from_type(cls, class_type):
        """Return the class associated with input type.

        This will NOT check for classes with duplicated class type.
        The first class found with matching type will be returned.

        Parameters
        ----------
        class_type : str
            Type of the class which will be looked up for.

        Returns
        -------
        class_obj : class
            Desired class, if found. This is NOT an instance of the class.

        """
        # Why this method is a classmethod? Just an exception for simplicity
        # classmethods should normally return an instance of calling class
        if cls.__super__ != cls.__name__:
            raise TypeError("only superclasses can be used.")

        # Get all the subclasses of the superclass
        subclasses = cls.get_subclasses()

        # Look for desired class type
        for class_data in subclasses:
            if get_private(class_data[1], 'class_type', None) == class_type:
                return class_data[1]

        raise NameError("no class of type `{:}` found within the package "
                        "of class '{:}'".format(class_type, cls.__module__))
Esempio n. 3
0
 def class_type(self):
     """Defines class type."""
     try:  # Convert the private attribute to public property
         return get_private(self.__class__, 'class_type')
     except AttributeError:
         raise AttributeError("'class_type' not defined for '{:}'"
                              "".format(self.__class__.__name__))
Esempio n. 4
0
def import_class_types(classes):
    """Returns types associated with input list of classes.

    Abstract properties are ignored.

    Returns
    -------
    types : list
        List of class types associated with input list of classes.

    """
    # Get all class types from the input list of classes (to check duplicates)
    # Leaving out the classes not defining a class_type
    class_types = map(
        lambda class_file: get_private(class_file[1], 'class_type', None),
        classes)
    # skipping non string class_types -> classes not supporting creator
    return [class_type for class_type in
            class_types if isinstance(class_type, str)]
Esempio n. 5
0
    def create(cls, class_item=None, *args, **kwargs):
        """This method creates an instance of a class with given type.

        The list of subclasses of calling superclass is looked for any class
        defining `class_item = 'value'`. If found, the class type is listed.

        Also a class instance can be passed as main argument.
        In this case the class instance is returned as is.

        Parameters
        ----------
        class_item : str or class instance or None, optional
            Type of the class to instantiate.
            If a class instance of cls is passed, instead, it returns
            the instance directly.
            If this is None, an instance of the classing superclass is created.
        args, kwargs : optional arguments
            Any other argument for the class to create.
            If a class instance is passed as `class_item`,
            optional arguments are NOT allowed.

        Returns
        -------
        instance_class : any class
            Instance of the class having the given type (`class_type`)
            or the same class instance passed as input.

        """
        if cls.__super__ != cls.__name__:
            raise TypeError("classes can be created from superclasses only.")

        # Create an instance of the calling superclass
        if class_item is None:
            return cls(*args, **kwargs)  # Pycharm says are unexpected args

        # We accept strings and class instances only
        if isclass(class_item):  # Returns false for instances
            raise TypeError("creator only accepts a class type "
                            "as string or a class instance.")

        # CCreator cannot be created!
        if class_item.__class__ == CCreator:
            raise TypeError("class 'CCreator' is not callable.")

        # If a class instance is passed, it's returned as is
        if not is_str(class_item):
            if not isinstance(class_item, cls):
                raise TypeError("input instance should be a {:} "
                                "subclass.".format(cls.__name__))
            if len(args) + len(kwargs) != 0:
                raise TypeError("optional arguments are not allowed "
                                "when a class instance is passed.")
            return class_item

        # Get all the subclasses of the superclass
        subclasses = cls.get_subclasses()

        # Get all class types from the list of subclasses (to check duplicates)
        class_types = import_class_types(subclasses)

        # Check for duplicates
        _check_class_types_duplicates(class_types, subclasses)

        # Everything seems fine now, look for desired class type
        for class_data in subclasses:
            if get_private(class_data[1], 'class_type', None) == class_item:
                return class_data[1](*args, **kwargs)

        raise NameError("no class of type `{:}` is a subclass of '{:}' "
                        "from module '{:}'".format(
                            class_item, cls.__name__, cls.__module__))