def _process_args(args, kwargs, prefer_local=True, recurse=True):
this_engine = distob.engine.eid<EOL>local_args = []<EOL>remote_args = []<EOL>execloc = this_engine  <EOL>for a in args:<EOL><INDENT>id = None<EOL>if isinstance(a, Remote):<EOL><INDENT>id = a._ref.id<EOL><DEDENT>elif isinstance(a, Ref):<EOL><INDENT>id = a.id<EOL><DEDENT>elif isinstance(a, Id):<EOL><INDENT>id = a<EOL><DEDENT>if id is not None:<EOL><INDENT>if id.engine is this_engine:<EOL><INDENT>local_args.append(distob.engine[id])<EOL>remote_args.append(distob.engine[id])<EOL><DEDENT>else:<EOL><INDENT>if (prefer_local and isinstance(a, Remote) and <EOL>a._obcache_current):<EOL><INDENT>local_args.append(a._obcache)<EOL>remote_args.append(id)<EOL><DEDENT>else:<EOL><INDENT>if execloc is not this_engine and id.engine is not execloc:<EOL><INDENT>raise DistobValueError(<EOL>'<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>execloc = id.engine<EOL>local_args.append(None)<EOL>remote_args.append(id)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>elif (isinstance(a, collections.Sequence) and<EOL>not isinstance(a, string_types) and recurse):<EOL><INDENT>eid, ls, _ = _process_args(a, {}, prefer_local, recurse=False)<EOL>if eid is not this_engine:<EOL><INDENT>if execloc is not this_engine and eid is not execloc:<EOL><INDENT>raise DistobValueError(<EOL>'<STR_LIT>')<EOL><DEDENT>execloc = eid<EOL><DEDENT>local_args.append(ls)<EOL>remote_args.append(ls)<EOL><DEDENT>else:<EOL><INDENT>local_args.append(a)<EOL>remote_args.append(a)<EOL><DEDENT><DEDENT>local_kwargs = dict()<EOL>remote_kwargs = dict()<EOL>for k, a in kwargs.items():<EOL><INDENT>id = None<EOL>if isinstance(a, Remote):<EOL><INDENT>id = a._ref.id<EOL><DEDENT>elif isinstance(a, Ref):<EOL><INDENT>id = a.id<EOL><DEDENT>elif isinstance(a, Id):<EOL><INDENT>id = a<EOL><DEDENT>if id is not None:<EOL><INDENT>if id.engine is this_engine:<EOL><INDENT>local_kwargs[k] = distob.engine[id]<EOL>remote_kwargs[k] = distob.engine[id]<EOL><DEDENT>else:<EOL><INDENT>if (prefer_local and isinstance(a, Remote) and<EOL>a._obcache_current):<EOL><INDENT>local_kwargs[k] = a._obcache<EOL>remote_kwargs[k] = id<EOL><DEDENT>else:<EOL><INDENT>if execloc is not this_engine and id.engine is not execloc:<EOL><INDENT>raise DistobValueError(<EOL>'<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>execloc = id.engine<EOL>local_kwargs[k] = None<EOL>remote_kwargs[k] = id<EOL><DEDENT><DEDENT><DEDENT><DEDENT>elif (isinstance(a, collections.Sequence) and<EOL>not isinstance(a, string_types) and recurse):<EOL><INDENT>eid, ls, _ = _process_args(a, {}, prefer_local, recurse=False)<EOL>if eid is not this_engine:<EOL><INDENT>if execloc is not this_engine and eid is not execloc:<EOL><INDENT>raise DistobValueError(<EOL>'<STR_LIT>')<EOL><DEDENT>execloc = eid<EOL><DEDENT>local_kwargs[k] = ls<EOL>remote_kwargs[k] = ls<EOL><DEDENT>else:<EOL><INDENT>local_kwargs[k] = a<EOL>remote_kwargs[k] = a<EOL><DEDENT><DEDENT>if execloc is this_engine:<EOL><INDENT>return execloc, tuple(local_args), local_kwargs<EOL><DEDENT>else:<EOL><INDENT>return execloc, tuple(remote_args), remote_kwargs<EOL><DEDENT>
Select local or remote execution and prepare arguments accordingly.
    Assumes any remote args have already been moved to a common engine.

    Local execution will be chosen if:
    - all args are ordinary objects or Remote instances on the local engine; or
    - the local cache of all remote args is current, and prefer_local is True.
    Otherwise, remote execution will be chosen. 

    For remote execution, replaces any remote arg with its Id.
    For local execution, replaces any remote arg with its locally cached object
    Any arguments or kwargs that are Sequences will be recursed one level deep.

    Args:
      args (list)
      kwargs (dict)
      prefer_local (bool, optional): Whether cached local results are prefered
        if available, instead of returning Remote objects. Default is True.