def progress_loop(func, items, factory, *args, **kwargs):
    """
    This will iterate over ``items`` and call ``func`` for each.  If a progress
    ``factory`` kwarg is provided, then a progress instance will be created and
    updated along the way.
    """
    message = kwargs.pop('message', None)
    count = kwargs.pop('count', None)
    allow_cancel = kwargs.pop('allow_cancel', False)
    if count is None:
        try:
            count = len(items)
        except TypeError:
            count = items.count()
    if not count:
        return True
    prog = None
    if factory:
        prog = factory(message, count)
    canceled = False
    for i, item in enumerate(items, 1):
        func(item, i, *args, **kwargs)
        if prog and not prog.update(i):
            canceled = True
            break
    if prog:
        prog.finish()
    if canceled and not allow_cancel:
        raise RuntimeError('Operation was canceled')
    return not canceled
