def _parse_specs(specs, Ks):
funcs = {}<EOL>metas = {}<EOL>meta_deps = defaultdict(set)<EOL>def add_func(func, alpha=None, pos=None):<EOL><INDENT>needs_alpha = getattr(func, '<STR_LIT>', False)<EOL>is_meta = hasattr(func, '<STR_LIT>')<EOL>d = metas if is_meta else funcs<EOL>if func not in d:<EOL><INDENT>if needs_alpha:<EOL><INDENT>args = {'<STR_LIT>': [alpha], '<STR_LIT>': [pos]}<EOL><DEDENT>else:<EOL><INDENT>args = {'<STR_LIT>': None, '<STR_LIT>': [pos]}<EOL><DEDENT>if not is_meta:<EOL><INDENT>d[func] = _FuncInfo(**args)<EOL><DEDENT>else:<EOL><INDENT>d[func] = _MetaFuncInfo(deps=[], **args)<EOL>for req in func.needs_results:<EOL><INDENT>if callable(req.alpha):<EOL><INDENT>req_alpha = req.alpha(alpha)<EOL><DEDENT>else:<EOL><INDENT>req_alpha = req.alpha<EOL><DEDENT>add_func(req.func, alpha=req_alpha)<EOL>meta_deps[func].add(req.func)<EOL>meta_deps[req.func]  <EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>info = d[func]<EOL>if not needs_alpha:<EOL><INDENT>if pos is not None:<EOL><INDENT>if info.pos != [None]:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg.format(func_name))<EOL><DEDENT>info.pos[<NUM_LIT:0>] = pos<EOL><DEDENT><DEDENT>else:  <EOL><INDENT>try:<EOL><INDENT>idx = info.alphas.index(alpha)<EOL><DEDENT>except ValueError:<EOL><INDENT>info.alphas.append(alpha)<EOL>info.pos.append(pos)<EOL>if is_meta:<EOL><INDENT>for req in func.needs_results:<EOL><INDENT>if callable(req.alpha):<EOL><INDENT>req_alpha = req.alpha(alpha)<EOL><DEDENT>else:<EOL><INDENT>req_alpha = req.alpha<EOL><DEDENT>add_func(req.func, alpha=req_alpha)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if pos is not None:<EOL><INDENT>if info.pos[idx] is not None:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg.format(func_name, alpha))<EOL><DEDENT>info.pos[idx] = pos<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>for i, spec in enumerate(specs):<EOL><INDENT>func_name, alpha = (spec.split('<STR_LIT::>', <NUM_LIT:1>) + [None])[:<NUM_LIT:2>]<EOL>if alpha is not None:<EOL><INDENT>alpha = float(alpha)<EOL><DEDENT>try:<EOL><INDENT>func = func_mapping[func_name]<EOL><DEDENT>except KeyError:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg.format(func_name))<EOL><DEDENT>needs_alpha = getattr(func, '<STR_LIT>', False)<EOL>if needs_alpha and alpha is None:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg.format(func_name, spec))<EOL><DEDENT>elif not needs_alpha and alpha is not None:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg.format(func_name, spec))<EOL><DEDENT>add_func(func, alpha, i)<EOL><DEDENT>meta_counter = itertools.count(-<NUM_LIT:1>, step=-<NUM_LIT:1>)<EOL>for info in itertools.chain(itervalues(funcs), itervalues(metas)):<EOL><INDENT>for i, pos in enumerate(info.pos):<EOL><INDENT>if pos is None:<EOL><INDENT>info.pos[i] = next(meta_counter)<EOL><DEDENT><DEDENT><DEDENT>for func, info in iteritems(metas):<EOL><INDENT>deps = info.deps<EOL>assert deps == []<EOL>for req in func.needs_results:<EOL><INDENT>f = req.func<EOL>req_info = (metas if hasattr(f, '<STR_LIT>') else funcs)[f]<EOL>if req.alpha is not None:<EOL><INDENT>if callable(req.alpha):<EOL><INDENT>req_alpha = req.alpha(info.alphas)<EOL><DEDENT>else:<EOL><INDENT>req_alpha = req.alpha<EOL><DEDENT>find_alpha = np.vectorize(req_info.alphas.index, otypes=[int])<EOL>pos = np.asarray(req_info.pos)[find_alpha(req_alpha)]<EOL>if np.isscalar(pos):<EOL><INDENT>deps.append(pos[()])<EOL><DEDENT>else:<EOL><INDENT>deps.extend(pos)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>pos, = req_info.pos<EOL>deps.append(pos)<EOL><DEDENT><DEDENT><DEDENT>meta_order = topological_sort(meta_deps)<EOL>metas_ordered = OrderedDict(<EOL>(f, metas[f]) for f in meta_order if hasattr(f, '<STR_LIT>'))<EOL>return funcs, metas_ordered, -next(meta_counter) - <NUM_LIT:1><EOL>
Set up the different functions we need to call.

Returns:
    - a dict mapping base estimator functions to _FuncInfo objects.
      If the function needs_alpha, then the alphas attribute is an array
      of alpha values and pos is a corresponding array of indices.
      Otherwise, alphas is None and pos is a list containing a single index.
      Indices are >= 0 if they correspond to something in a spec,
      and negative if they're just used for a meta estimator but not
      directly requested.
    - an OrderedDict mapping functions to _MetaFuncInfo objects.
      alphas and pos are like for _FuncInfo; deps is a list of indices
      which should be passed to the estimator. Note that these might be
      other meta functions; this list is guaranteed to be in an order
      such that all dependencies are resolved before calling that function.
      If no such order is possible, raise ValueError.
    - the number of meta-only results

# TODO: update doctests for _parse_specs

>>> _parse_specs(['renyi:.8', 'hellinger', 'renyi:.9'])
({<function alpha_div at 0x10954f848>:
        _FuncInfo(alphas=[0.8, 0.5, 0.9], pos=[-1, -2, -3])},
 OrderedDict([
    (<function hellinger at 0x10954fc80>,
        _MetaFuncInfo(alphas=None, pos=[1], deps=[array(-2)])),
    (<function renyi at 0x10954fcf8>,
        _MetaFuncInfo(alphas=[0.8, 0.9], pos=[0, 2], deps=[-1, -3]))
 ]), 3)

>>> _parse_specs(['renyi:.8', 'hellinger', 'renyi:.9', 'l2'])
({<function alpha_div at 0x10954f848>:
    _FuncInfo(alphas=[0.8, 0.5, 0.9], pos=[-1, -2, -3]),
  <function linear at 0x10954f758>: _FuncInfo(alphas=None, pos=[-4])
 }, OrderedDict([
    (<function hellinger at 0x10954fc80>,
        _MetaFuncInfo(alphas=None, pos=[1], deps=[array(-2)])),
    (<function l2 at 0x10954fde8>,
        _MetaFuncInfo(alphas=None, pos=[3], deps=[-4])),
    (<function renyi at 0x10954fcf8>,
        _MetaFuncInfo(alphas=[0.8, 0.9], pos=[0, 2], deps=[-1, -3]))
 ]), 4)

>>> _parse_specs(['renyi:.8', 'hellinger', 'renyi:.9', 'l2', 'linear'])
({<function alpha_div at 0x10954f848>:
    _FuncInfo(alphas=[0.8, 0.5, 0.9], pos=[-1, -2, -3]),
  <function linear at 0x10954f758>: _FuncInfo(alphas=None, pos=[4])
 }, OrderedDict([
    (<function hellinger at 0x10954fc80>,
        _MetaFuncInfo(alphas=None, pos=[1], deps=[array(-2)])),
    (<function l2 at 0x10954fde8>,
        _MetaFuncInfo(alphas=None, pos=[3], deps=[4])),
    (<function renyi at 0x10954fcf8>,
        _MetaFuncInfo(alphas=[0.8, 0.9], pos=[0, 2], deps=[-1, -3]))
 ]), 3)