def pipeline(error_func=None, use_builders=False):
    functions_list = []

    def add_func(func, group):
        """ Functions_list is a list of tuples to maintain order.
            Originally it was an OrderedDict, but that became out of order
            when you did group1 group2 group1.
        """
        functions_list.append((group, func.__name__, func))
        return func

    def function_annotator(group=''):
        if callable(group):
            return add_func(group, '')
        else:
            return lambda func: add_func(func, group)

    def get_functions_to_run(functions=functions_list, function_groups_to_skip=None):
        if function_groups_to_skip is None:
            function_groups_to_skip = []
        functions_to_run = [fn for group, _, fn in functions if group not in function_groups_to_skip]

        if use_builders:
            def build(fn):
                fn = fn()
                assert callable(fn), \
                    "Pipeless annotated functions should build a function when use_builders=True"
                return fn

            functions_to_run = [build(fn) for fn in functions_to_run]

        return functions_to_run

    def run_pipeline(item_generator=None, functions_to_run=None, function_groups_to_skip=None):
        def safe_source(source, error_func):
            item = None
            try:
                for item in source:
                    yield item
            except Exception as e:
                if error_func is None:
                    raise
                error_func(item, e)
                raise StopIteration

        if functions_to_run is None:
            functions_to_run = get_functions_to_run(function_groups_to_skip=function_groups_to_skip)

        for item in safe_source(item_generator, error_func):
            should_yield = True
            for fn_num, function in enumerate(functions_to_run):
                try:
                    item = function(item)
                except Exception as exception:
                    if error_func is None:
                        raise
                    item = error_func(item, exception)

                if item is None:
                    should_yield = False
                    break
                if isinstance(item, GeneratorType):
                    should_yield = False
                    for i in run_pipeline(item, functions_to_run[fn_num + 1:], function_groups_to_skip):
                        yield i
                    break
            if should_yield:
                yield item

    return function_annotator, run_pipeline, functions_list
Drops database from sqlalchemy models.
dataset/ETHPy150Open andychase/pipeless/pipeless.py/pipeline--crossover with--dataset/ETHPy150Open openstack/compass-core/bin/manage_db.py/dropdb