def test():
    '''Test basic workings of `is_iterable`.'''
    
    iterables = [
        [1, 2, 3],
        (1, 2),
        {},
        (),
        [[1]],
        'asdfasdf',
        ''
    ]
    
    non_iterables = [
        dict,
        list,
        type,
        None,
        True,
        False,
        Exception,
        lambda x: x
    ]
    
    for iterable in iterables:
        assert is_iterable(iterable)
        
    for non_iterable in non_iterables:
        assert not is_iterable(non_iterable)
Beispiel #2
0
def test():
    '''Test basic workings of `is_iterable`.'''

    iterables = [
        [1, 2, 3],
        (1, 2),
        {},
        (),
        [[1]],
        'asdfasdf',
        ''
    ]

    non_iterables = [
        dict,
        list,
        type,
        None,
        True,
        False,
        Exception,
        lambda x: x
    ]

    for iterable in iterables:
        assert is_iterable(iterable)

    for non_iterable in non_iterables:
        assert not is_iterable(non_iterable)
Beispiel #3
0
def reverse_with_set_values(d, sort=False):
    '''
    Reverse the dict, with the values of the new dict being sets.
    
    Example:
    
        reverse_with_set_values({1: 2, 3: 4, 'meow': 2}) == \
                                                       {2: {1, 'meow'}, 4: {3}}
            
    Instead of a dict you may also input a tuple in which the first item is an
    iterable and the second item is either a key function or an attribute name.
    A dict will be constructed from these and used.
    
    If you'd like the result dict to be sorted, pass `sort=True`, and you'll
    get a sorted `OrderedDict`. You can also specify the sorting key function
    or attribute name as the `sort` argument.
    '''
    ### Pre-processing input: #################################################
    #                                                                         #
    if hasattr(d, 'items'): # `d` is a dict
        fixed_dict = d
    else: # `d` is not a dict
        assert cute_iter_tools.is_iterable(d) and len(d) == 2
        iterable, key_function_or_attribute_name = d
        assert cute_iter_tools.is_iterable(iterable)
        key_function = comparison_tools.process_key_function_or_attribute_name(
            key_function_or_attribute_name
        )
        fixed_dict = {key: key_function(key) for key in iterable}
    #                                                                         #
    ### Finished pre-processing input. ########################################
    
    new_dict = {}
    for key, value in fixed_dict.items():
        if value not in new_dict:
            new_dict[value] = []
        new_dict[value].append(key)
    
    # Making into sets:
    for key, value in new_dict.copy().items():
        new_dict[key] = set(value)
        
    if sort:
        from python_toolbox import nifty_collections
        ordered_dict = nifty_collections.OrderedDict(new_dict)
        if isinstance(sort, (collections.Callable, str)):
            key_function = comparison_tools. \
                                   process_key_function_or_attribute_name(sort)
        else:
            assert sort is True
            key_function = None
        ordered_dict.sort(key_function)
        return ordered_dict
    else:
        return new_dict
Beispiel #4
0
def reverse_with_set_values(d, sort=False):
    '''
    Reverse the dict, with the values of the new dict being sets.
    
    Example:
    
        reverse_with_set_values({1: 2, 3: 4, 'meow': 2}) == \
                                                       {2: {1, 'meow'}, 4: {3}}
            
    Instead of a dict you may also input a tuple in which the first item is an
    iterable and the second item is either a key function or an attribute name.
    A dict will be constructed from these and used.
    
    If you'd like the result dict to be sorted, pass `sort=True`, and you'll
    get a sorted `OrderedDict`. You can also specify the sorting key function
    or attribute name as the `sort` argument.
    '''
    ### Pre-processing input: #################################################
    #                                                                         #
    if hasattr(d, 'items'): # `d` is a dict
        fixed_dict = d
    else: # `d` is not a dict
        assert cute_iter_tools.is_iterable(d) and len(d) == 2
        iterable, key_function_or_attribute_name = d
        assert cute_iter_tools.is_iterable(iterable)
        key_function = comparison_tools.process_key_function_or_attribute_name(
            key_function_or_attribute_name
        )
        fixed_dict = {key: key_function(key) for key in iterable}
    #                                                                         #
    ### Finished pre-processing input. ########################################
    
    new_dict = {}
    for key, value in fixed_dict.iteritems():
        if value not in new_dict:
            new_dict[value] = []
        new_dict[value].append(key)
    
    # Making into sets:
    for key, value in new_dict.copy().iteritems():
        new_dict[key] = set(value)
        
    if sort:
        from python_toolbox import nifty_collections
        ordered_dict = nifty_collections.OrderedDict(new_dict)
        if isinstance(sort, (collections.Callable, basestring)):
            key_function = comparison_tools. \
                                   process_key_function_or_attribute_name(sort)
        else:
            assert sort is True
            key_function = None
        ordered_dict.sort(key_function)
        return ordered_dict
    else:
        return new_dict
    def __init__(self, function):
        '''
        Construct the `TempFunctionCallCounter`.
        
        For `function`, you may pass in either a function object, or a
        `(parent_object, function_name)` pair, or a `(getter, setter)` pair.
        '''

        if cute_iter_tools.is_iterable(function):
            first, second = function
            if isinstance(second, str):
                actual_function = getattr(first, second)
            else:
                assert callable(first) and callable(second)
                actual_function = first(
                )  # `first` is the getter in this case.

        else:  # not cute_iter_tools.is_iterable(function)
            assert callable(function)
            actual_function = function
            try:
                address = address_tools.object_to_string.get_address(function)
                parent_object_address, function_name = address.rsplit('.', 1)
                parent_object = address_tools.resolve(parent_object_address)
            except Exception:
                raise Exception("Couldn't obtain parent/name pair from "
                                "function; supply one manually or "
                                "alternatively supply a getter/setter pair.")
            first, second = parent_object, function_name

        self.call_counting_function = count_calls(actual_function)

        TempValueSetter.__init__(self, (first, second),
                                 value=self.call_counting_function)
    def __init__(self, function):
        """
        Construct the `TempFunctionCallCounter`.
        
        For `function`, you may pass in either a function object, or a
        `(parent_object, function_name)` pair, or a `(getter, setter)` pair.
        """

        if cute_iter_tools.is_iterable(function):
            first, second = function
            if isinstance(second, basestring):
                actual_function = getattr(first, second)
            else:
                assert callable(first) and callable(second)
                actual_function = first()  # `first` is the getter in this case.

        else:  # not cute_iter_tools.is_iterable(function)
            assert callable(function)
            actual_function = function
            try:
                address = address_tools.object_to_string.get_address(function)
                parent_object_address, function_name = address.rsplit(".", 1)
                parent_object = address_tools.resolve(parent_object_address)
            except Exception:
                raise Exception(
                    "Couldn't obtain parent/name pair from "
                    "function; supply one manually or "
                    "alternatively supply a getter/setter pair."
                )
            first, second = parent_object, function_name

        self.call_counting_function = count_calls(actual_function)

        TempValueSetter.__init__(self, (first, second), value=self.call_counting_function)
Beispiel #7
0
    def __init__(self, inputs=(), outputs=(), name=None):
        '''
        Construct the emitter.
        
        `inputs` is a list of inputs, all of them must be emitters.
        
        `outputs` is a list of outputs, they must be either emitters or
        callables.
        
        `name` is a string name for the emitter.
        '''

        assert cute_iter_tools.is_iterable(inputs) and \
               cute_iter_tools.is_iterable(outputs)
        
        self._inputs = set()
        '''The emitter's inputs.'''
        
        self._outputs = set()
        '''The emitter's inputs.'''
        
        for output in outputs:
            self.add_output(output)
                        
        self.__total_callable_outputs_cache = None
        '''
        A cache of total callable outputs.
        
        This means the callable outputs of this emitter and any output
        emitters.
        '''
        
        self._recalculate_total_callable_outputs()        

        # We made sure to create the callable outputs cache before we add
        # inputs, so when we update their cache, it could use ours.
        for input in inputs:
            self.add_input(input)

        self.name = name
        '''The emitter's name.'''
Beispiel #8
0
    def __init__(self, inputs=(), outputs=(), name=None):
        '''
        Construct the emitter.
        
        `inputs` is a list of inputs, all of them must be emitters.
        
        `outputs` is a list of outputs, they must be either emitters or
        callables.
        
        `name` is a string name for the emitter.
        '''

        assert cute_iter_tools.is_iterable(inputs) and \
               cute_iter_tools.is_iterable(outputs)

        self._inputs = set()
        '''The emitter's inputs.'''

        self._outputs = set()
        '''The emitter's inputs.'''

        for output in outputs:
            self.add_output(output)

        self.__total_callable_outputs_cache = None
        '''
        A cache of total callable outputs.
        
        This means the callable outputs of this emitter and any output
        emitters.
        '''

        self._recalculate_total_callable_outputs()

        # We made sure to create the callable outputs cache before we add
        # inputs, so when we update their cache, it could use ours.
        for input in inputs:
            self.add_input(input)

        self.name = name
        '''The emitter's name.'''
Beispiel #9
0
def is_subclass(candidate, base_class):
    '''
    Check if `candidate` is a subclass of `base_class`.
    
    You may pass in a tuple of base classes instead of just one, and it will
    check whether `candidate` is a subclass of any of these base classes.
    
    This has the advantage that it doesn't throw an exception if `candidate` is
    not a type. (Python issue 10569.)        
    '''
    # todo: disable ability to use nested iterables.
    if cute_iter_tools.is_iterable(base_class):
        return any(is_subclass(candidate, single_base_class) for 
                   single_base_class in base_class)
    elif not isinstance(candidate, (type, types.ClassType)):
        return False
    else:
        return issubclass(candidate, base_class)
def is_subclass(candidate, base_class):
    '''
    Check if `candidate` is a subclass of `base_class`.
    
    You may pass in a tuple of base classes instead of just one, and it will
    check whether `candidate` is a subclass of any of these base classes.
    
    This has the advantage that it doesn't throw an exception if `candidate` is
    not a type. (Python issue 10569.)
    '''
    # todo: disable ability to use nested iterables.
    if cute_iter_tools.is_iterable(base_class):
        return any(
            is_subclass(candidate, single_base_class)
            for single_base_class in base_class)
    elif not isinstance(candidate, type):
        return False
    else:
        return issubclass(candidate, base_class)
Beispiel #11
0
def get_equivalence_classes(iterable, key=None, container=set, *,
                            use_ordered_dict=False, sort_ordered_dict=False):
    '''
    Divide items in `iterable` to equivalence classes, using the key function.

    Each item will be put in a set with all other items that had the same
    result when put through the `key` function.

    Example:

        >>> get_equivalence_classes(range(10), lambda x: x % 3)
        {0: {0, 9, 3, 6}, 1: {1, 4, 7}, 2: {8, 2, 5}}


    Returns a `dict` with keys being the results of the function, and the
    values being the sets of items with those values.

    Alternate usages:

        Instead of a key function you may pass in an attribute name as a
        string, and that attribute will be taken from each item as the key.

        Instead of an iterable and a key function you may pass in a `dict` (or
        similar mapping) into `iterable`, without specifying a `key`, and the
        value of each item in the `dict` will be used as the key.

        Example:

            >>> get_equivalence_classes({1: 2, 3: 4, 'meow': 2})
            {2: {1, 'meow'}, 4: {3}}


    If you'd like the result to be in an `OrderedDict`, specify
    `use_ordered_dict=True`, and the items will be ordered according to
    insertion order. If you'd like that `OrderedDict` to be sorted, pass in
    `sort_ordered_dict=True`. (It automatically implies
    `use_ordered_dict=True`.) You can also pass in a sorting key function or
    attribute name as the `sort_ordered_dict` argument.
    '''

    from python_toolbox import comparison_tools

    ### Pre-processing input: #################################################
    #                                                                         #
    if key is None:
        if isinstance(iterable, collections.abc.Mapping):
            d = iterable
        else:
            try:
                d = dict(iterable)
            except ValueError:
                raise Exception(
                    "You can't put in a non-dict without also supplying a "
                    "`key` function. We need to know which key to use."
                )
    else: # key is not None
        assert cute_iter_tools.is_iterable(iterable)
        key_function = comparison_tools.process_key_function_or_attribute_name(
            key
        )
        d = {key: key_function(key) for key in iterable}
    #                                                                         #
    ### Finished pre-processing input. ########################################

    if use_ordered_dict or sort_ordered_dict:
        from python_toolbox import nifty_collections
        new_dict = nifty_collections.OrderedDict()
    else:
        new_dict = {}
    for key, value in d.items():
        new_dict.setdefault(value, []).append(key)

    # Making into desired container:
    for key, value in new_dict.copy().items():
        new_dict[key] = container(value)

    if sort_ordered_dict:
        if isinstance(sort_ordered_dict, (collections.abc.Callable, str)):
            key_function = comparison_tools. \
                      process_key_function_or_attribute_name(sort_ordered_dict)
            new_dict.sort(key_function)
        elif sort_ordered_dict is True:
            new_dict.sort()
        return new_dict

    else:
        return new_dict
Beispiel #12
0
def get_equivalence_classes(iterable, key=None, container=set, 
                            use_ordered_dict=False, sort_ordered_dict=False):
    '''
    Divide items in `iterable` to equivalence classes, using the key function.
    
    Each item will be put in a set with all other items that had the same
    result when put through the `key` function.
    
    Example:
    
        >>> get_equivalence_classes(range(10), lambda x: x % 3)
        {0: {0, 9, 3, 6}, 1: {1, 4, 7}, 2: {8, 2, 5}}
        
    
    Returns a `dict` with keys being the results of the function, and the
    values being the sets of items with those values.
    
    Alternate usages:
    
        Instead of a key function you may pass in an attribute name as a
        string, and that attribute will be taken from each item as the key.
        
        Instead of an iterable and a key function you may pass in a `dict` (or
        similar mapping) into `iterable`, without specifying a `key`, and the
        value of each item in the `dict` will be used as the key.
        
        Example:
        
            >>> get_equivalence_classes({1: 2, 3: 4, 'meow': 2})
            {2: {1, 'meow'}, 4: {3}}
            
    
    If you'd like the result to be in an `OrderedDict`, specify
    `use_ordered_dict=True`, and the items will be ordered according to
    insertion order. If you'd like that `OrderedDict` to be sorted, pass in
    `sort_ordered_dict=True`. (It automatically implies
    `use_ordered_dict=True`.) You can also pass in a sorting key function or
    attribute name as the `sort_ordered_dict` argument.
    '''
    
    from python_toolbox import comparison_tools
    
    ### Pre-processing input: #################################################
    #                                                                         #
    if key is None:
        if isinstance(iterable, collections.Mapping):
            d = iterable
        else:
            try:
                d = dict(iterable)
            except ValueError:
                raise Exception(
                    "You can't put in a non-dict without also supplying a "
                    "`key` function. We need to know which key to use."
                )
    else: # key is not None
        assert cute_iter_tools.is_iterable(iterable)
        key_function = comparison_tools.process_key_function_or_attribute_name(
            key
        )
        d = dict((key, key_function(key)) for key in iterable)
    #                                                                         #
    ### Finished pre-processing input. ########################################
    
    if use_ordered_dict or sort_ordered_dict:
        from python_toolbox import nifty_collections
        new_dict = nifty_collections.OrderedDict()
    else:
        new_dict = {}
    for key, value in d.items():
        new_dict.setdefault(value, []).append(key)
    
    # Making into desired container:
    for key, value in new_dict.copy().items():
        new_dict[key] = container(value)
        
    if sort_ordered_dict:
        if isinstance(sort_ordered_dict, (collections.Callable, str)):
            key_function = comparison_tools. \
                      process_key_function_or_attribute_name(sort_ordered_dict)
            new_dict.sort(key_function)
        elif sort_ordered_dict is True:
            new_dict.sort()
        return new_dict
    
    else:
        return new_dict