# Path: generators/iterable.py
# @noglobals
# def iterable(target):
#     ''' returns true if the given argument is iterable '''
#     if any(i in ('next', '__next__', '__iter__') for i in dir(target)):
#         return True
#     else:
#         try:
#             iter(target)
#             return True
#         except:
#             return False
# 
# Path: generators/map.py
# @strict_globals(function_arg_count=function_arg_count, multi_ops=multi_ops, window=window)
# def map(*args):
#     """ this map works just like the builtin.map, except, this one you can also:
#         - give it multiple functions to map over an iterable
#         - give it a single function with multiple arguments to run a window
#           based map operation over an iterable
#     """
# 
#     functions_to_apply = [i for i in args if callable(i)]
#     iterables_to_run = [i for i in args if not callable(i)]
#     #print('functions_to_apply:',functions_to_apply)
#     #print('iterables_to_run:',iterables_to_run)
# 
#     assert len(functions_to_apply)>0, 'at least one function needs to be given to map'
#     assert len(iterables_to_run)>0, 'no iterables were given to map'
# 
#     # check for native map usage
#     if len(functions_to_apply) == 1 and len(iterables_to_run) >= 1 and function_arg_count(*functions_to_apply)==1:
#         if hasattr(iter([]), '__next__'): # if python 3
#             return __builtins__.map(functions_to_apply[0], *iterables_to_run)
#         else:
#             return iter(__builtins__.map(functions_to_apply[0], *iterables_to_run))
#     # ---------------------------- new logic below ----------------------------
#     # logic for a single function
#     elif len(functions_to_apply) == 1:
#         fn = functions_to_apply[0]
#         # if there is a single iterable, chop it up
#         if len(iterables_to_run) == 1:
#             return (fn(*i) for i in window(iterables_to_run[0], function_arg_count(functions_to_apply[0])))
#     # logic for more than 1 function
#     elif len(functions_to_apply) > 1 and len(iterables_to_run) == 1:
#         return multi_ops(*(iterables_to_run + functions_to_apply))
#     else:
#         raise ValueError('invalid usage of map()')


from .iterable import iterable
from .map import map
from strict_functions import strict_globals
    from time import time as ts
    from collections import defaultdict
    from window import window
    from iter_kv import iter_kv
# @Last Modified time: 2017-12-09 13:21:35

from __future__ import print_function
del print_function



@strict_globals(map=map, iterable=iterable)
def side_task(pipe, *side_jobs):
    ''' allows you to run a function in a pipeline without affecting the data '''
    # validate the input
    assert iterable(pipe), 'side_task needs the first argument to be iterable'
    for sj in side_jobs:
        assert callable(sj), 'all side_jobs need to be functions, not {}'.format(sj)
    # add a pass through function to side_jobs
    side_jobs = (lambda i:i ,) + side_jobs
    # run the pipeline
    for i in map(pipe, *side_jobs):
        yield i[0]

del iterable, strict_globals

if __name__ == '__main__':

    even_odd_sums = defaultdict(float)
    set_even_odd = even_odd_sums.__setitem__

    # this builds a pipeline of tuples as (index, timestamp)
    pipeline = map(range(30), lambda i:i, lambda i:ts())
    # this finds the difference between each timestamp

# Path: generators/iterable.py
# @noglobals
# def iterable(target):
#     ''' returns true if the given argument is iterable '''
#     if any(i in ('next', '__next__', '__iter__') for i in dir(target)):
#         return True
#     else:
#         try:
#             iter(target)
#             return True
#         except:
#             return False
# 
# Path: generators/map.py
# @strict_globals(function_arg_count=function_arg_count, multi_ops=multi_ops, window=window)
# def map(*args):
#     """ this map works just like the builtin.map, except, this one you can also:
#         - give it multiple functions to map over an iterable
#         - give it a single function with multiple arguments to run a window
#           based map operation over an iterable
#     """
# 
#     functions_to_apply = [i for i in args if callable(i)]
#     iterables_to_run = [i for i in args if not callable(i)]
#     #print('functions_to_apply:',functions_to_apply)
#     #print('iterables_to_run:',iterables_to_run)
# 
#     assert len(functions_to_apply)>0, 'at least one function needs to be given to map'
#     assert len(iterables_to_run)>0, 'no iterables were given to map'
# 
#     # check for native map usage
#     if len(functions_to_apply) == 1 and len(iterables_to_run) >= 1 and function_arg_count(*functions_to_apply)==1:
#         if hasattr(iter([]), '__next__'): # if python 3
#             return __builtins__.map(functions_to_apply[0], *iterables_to_run)
#         else:
#             return iter(__builtins__.map(functions_to_apply[0], *iterables_to_run))
#     # ---------------------------- new logic below ----------------------------
#     # logic for a single function
#     elif len(functions_to_apply) == 1:
#         fn = functions_to_apply[0]
#         # if there is a single iterable, chop it up
#         if len(iterables_to_run) == 1:
#             return (fn(*i) for i in window(iterables_to_run[0], function_arg_count(functions_to_apply[0])))
#     # logic for more than 1 function
#     elif len(functions_to_apply) > 1 and len(iterables_to_run) == 1:
#         return multi_ops(*(iterables_to_run + functions_to_apply))
#     else:
#         raise ValueError('invalid usage of map()')


# Path: generators/side_task.py
from .iterable import iterable
from .map import map
from strict_functions import strict_globals
    from time import time as ts
    from collections import defaultdict
    from window import window
    from iter_kv import iter_kv

# @Last Modified time: 2017-12-09 13:21:35

from __future__ import print_function
del print_function



@strict_globals(map=map, iterable=iterable)
def side_task(pipe, *side_jobs):
    ''' allows you to run a function in a pipeline without affecting the data '''
    # validate the input
    assert iterable(pipe), 'side_task needs the first argument to be iterable'
    for sj in side_jobs:
        assert callable(sj), 'all side_jobs need to be functions, not {}'.format(sj)
    # add a pass through function to side_jobs
    side_jobs = (lambda i:i ,) + side_jobs
    # run the pipeline
    for i in map(pipe, *side_jobs):
        yield i[0]

del iterable, strict_globals

if __name__ == '__main__':

    even_odd_sums = defaultdict(float)
    set_even_odd = even_odd_sums.__setitem__

    # this builds a pipeline of tuples as (index, timestamp)
    pipeline = map(range(30), lambda i:i, lambda i:ts())
    # this finds the difference between each timestamp

    pipeline = map(