docs: def _unpack_p0(p0, p0file, prior):
      """ Create proper p0.
  
      Try to read from a file. If that doesn't work, try using p0,
      and then, finally, the prior. If the p0 is from the file, it is
      checked against the prior to make sure that all elements have the
      right shape; if not the p0 elements are adjusted (using info from
      the prior) to be the correct shape. If p0 is a dictionary,
      keys in p0 that are not in prior are discarded. If p0 is True,
      then a random p0 is generated from the prior.
      """
      if p0file is not None:
          # p0 is a filename; read in values
          try:
              with open(p0file, "rb") as f:
                  p0 = pickle.load(f)
          except (IOError, EOFError):
              if prior is None:
                  raise IOError(
                      "No prior and can't read parameters from " + p0file
                      )
              else:
                  p0 = None
      if p0 is not None:
          # repackage as BufferDict or numpy array
          if p0 is True:
              p0 = next(_gvar.raniter(prior))
          if hasattr(p0, 'keys'):
              p0 = _gvar.BufferDict(p0)
              if p0.dtype != float:
                  p0.buf = numpy.asarray(p0.buf, dtype=float)
          else:
              p0 = numpy.array(p0, float)
      if prior is not None:
          # build new p0 from p0, plus the prior as needed
          pp = _reformat(prior, buf=[x.mean if x.mean != 0.0
                          else x.mean + 0.1 * x.sdev for x in prior.flat])
          if p0 is None:
              p0 = pp
          else:
              if pp.shape is not None:
                  # pp and p0 are arrays
                  pp_shape = pp.shape
                  p0_shape = p0.shape
                  if len(pp_shape)!=len(p0_shape):
                      raise ValueError(       #
                          "p0 and prior shapes incompatible: %s, %s"
                          % (str(p0_shape), str(pp_shape)))
                  idx = []
                  for npp, np0 in zip(pp_shape, p0_shape):
                      idx.append(slice(0, min(npp, np0)))
                  idx = tuple(idx)    # overlapping slices in each dir
                  pp[idx] = p0[idx]
                  p0 = pp
              else:
                  # pp and p0 are dicts
                  # if set(pp.keys()) != set(p0.keys()):
                  #     # mismatch in keys between prior and p0
                  #     raise ValueError("Key mismatch between prior and p0: "
                  #                      + ' '.join(str(k) for k in
                  #                      set(prior.keys()) ^ set(p0.keys())))
                  # adjust p0[k] to be compatible with shape of prior[k]
                  for k in pp:
                      if k not in p0:
                          continue
                      pp_shape = numpy.shape(pp[k])
                      p0_shape = numpy.shape(p0[k])
                      if len(pp_shape)!=len(p0_shape):
                          raise ValueError("p0 and prior incompatible: "
                                           +str(k))
                      if pp_shape == p0_shape:
                          pp[k] = p0[k]
                      else:
                          # find overlap between p0 and pp
                          pp_shape = pp[k].shape
                          p0_shape = p0[k].shape
                          if len(pp_shape)!=len(p0_shape):
                              raise ValueError(       #
                                  "p0 and prior incompatible: "+str(k))
                          idx = []
                          for npp, np0 in zip(pp_shape, p0_shape):
                              idx.append(slice(0, min(npp, np0)))
                          idx = tuple(idx)    # overlapping slices in each dir
                          pp[k][idx] = p0[k][idx]
                  p0 = pp
      if p0 is None:
          raise ValueError("No starting values for parameters")
      return p0