docs: def flatten(weights):
      """
      Flatten weights into a long DataFrame.
  
      Parameters
      ----------
      weights: pandas.DataFrame or dict
          A DataFrame of instrument weights with a MultiIndex where the top level
          contains pandas. Timestamps and the second level is instrument names.
          The columns consist of generic names. If dict is given this should be
          a dict of pandas.DataFrame in the above format, with keys for different
          root generics, e.g. 'CL'
  
      Returns
      -------
      A long DataFrame of weights, where columns are "date", "contract",
      "generic" and "weight". If a dictionary is passed, DataFrame will contain
      additional colum "key" containing the key value and be sorted according to
      this key value.
  
      Example
      -------
      >>> import pandas as pd
      >>> import mapping.util as util
      >>> vals = [[1, 0], [0, 1], [1, 0], [0, 1]]
      >>> widx = pd.MultiIndex.from_tuples([(pd.Timestamp('2015-01-03'), 'CLF5'),
      ...                                   (pd.Timestamp('2015-01-03'), 'CLG5'),
      ...                                   (pd.Timestamp('2015-01-04'), 'CLG5'),
      ...                                   (pd.Timestamp('2015-01-04'), 'CLH5')])
      >>> weights = pd.DataFrame(vals, index=widx, columns=["CL1", "CL2"])
      >>> util.flatten(weights)
      """  # NOQA
      if isinstance(weights, pd.DataFrame):
          wts = weights.stack().reset_index()
          wts.columns = ["date", "contract", "generic", "weight"]
      elif isinstance(weights, dict):
          wts = []
          for key in sorted(weights.keys()):
              wt = weights[key].stack().reset_index()
              wt.columns = ["date", "contract", "generic", "weight"]
              wt.loc[:, "key"] = key
              wts.append(wt)
          wts = pd.concat(wts, axis=0).reset_index(drop=True)
      else:
          raise ValueError("weights must be pd.DataFrame or dict")
  
      return wts