def exec_func_src(func, globals_=None, locals_=None, key_list=None,
                  sentinal=None, update=None, keys=None, verbose=False,
                  start=None, stop=None):
    """
    execs a func and returns requested local vars.

    Does not modify globals unless update=True (or in IPython)

    SeeAlso:
        ut.execstr_funckw
    """
    if keys is None:
        keys = key_list
    import utool as ut
    sourcecode = ut.get_func_sourcecode(func, stripdef=True, stripret=True)
    if update is None:
        update = ut.inIPython()
    if globals_ is None:
        globals_ = ut.get_parent_frame().f_globals
    if locals_ is None:
        locals_ = ut.get_parent_frame().f_locals
    if sentinal is not None:
        sourcecode = ut.replace_between_tags(sourcecode, '', sentinal)
    if start is not None or stop is not None:
        sourcecode = '\n'.join(sourcecode.splitlines()[slice(start, stop)])
    globals_new = globals_.copy()
    if locals_ is not None:
        globals_new.update(locals_)
        # globals_new.update({k: v for k, v in locals_.items()
        #                     if k not in globals_new})
    orig_globals = globals_new.copy()
    #six.exec_(sourcecode, globals_new, locals_)
    if verbose:
        print(ut.color_text(sourcecode, 'python'))
    six.exec_(sourcecode, globals_new)
    # Draw intermediate steps
    if keys is None:
        #return locals_
        # Remove keys created in function execution
        ut.delete_keys(globals_new, orig_globals.keys())
        if update:
            # update input globals?
            globals_.update(globals_new)
        # ~~ TODO autodetermine the keys from the function vars
        return globals_new
    else:
        if update:
            # update input globals?
            globals_.update(globals_new)
        #var_list = ut.dict_take(locals_, keys)
        var_list = ut.dict_take(globals_new, keys)
        return var_list