docs: def write(self, source=None, asframe=True, dtype=NP.float64,
                attributes='', reverse_obs=False, fromfreq=False, parse_time=True):
          '''Transfform a :class:`pandasdmx.model.DataMessage` instance to a pandas DataFrame
          or iterator over pandas Series.
  
          Args:
              source(pandasdmx.model.DataMessage): a pandasdmx.model.DataSet or iterator 
                  of pandasdmx.model.Series
  
              asframe(bool): if True, merge the series of values and/or attributes
                  into one or two multi-indexed
                  pandas.DataFrame(s), otherwise return an iterator of pandas.Series.
                  (default: True)
  
              dtype(str, NP.dtype, None): datatype for values. Defaults to NP.float64
                  if None, do not return the values of a series. In this case,
                  attributes must not be an empty string so that some attribute is returned.
  
              attributes(str, None): string determining which attributes, if any,
                  should be returned in separate series or a separate DataFrame.
                  Allowed values: '', 'o', 's', 'g', 'd'
                  or any combination thereof such as 'os', 'go'. Defaults to 'osgd'.
                  Where 'o', 's', 'g', and 'd' mean that attributes at observation,
                  series, group and dataset level will be returned as members of
                  per-observation namedtuples.
              reverse_obs(bool): if True, return observations in 
                  reverse order. Default: False
              fromfreq(bool): if True, extrapolate time periods 
                  from the first item and FREQ dimension. Default: False
              parse_time(bool): if True (default), try to generate datetime index, provided that
                  dim_at_obs is 'TIME' or 'TIME_PERIOD'. Otherwise, ``parse_time`` is ignored. If False,
                  always generate index of strings. 
                  Set it to False to increase performance and avoid 
                  parsing errors for exotic date-time formats unsupported by pandas.
          '''
  
          # Preparations
          dim_at_obs = self.msg.header.dim_at_obs
  
          # validate 'attributes'
          if attributes is None or attributes == False:
              attributes = ''
          else:
              try:
                  attributes = attributes.lower()
              except AttributeError:
                  raise TypeError("'attributes' argument must be of type str.")
              if set(attributes) - {'o', 's', 'g', 'd'}:
                  raise ValueError(
                      "'attributes' must only contain 'o', 's', 'd' or 'g'.")
  
          # Allow source to be either an iterable or a model.DataSet instance
          if hasattr(source, '__iter__'):
              iter_series = source
          elif hasattr(source, 'series'):
              iter_series = source.series
          elif hasattr(source, 'data') and dim_at_obs != 'AllDimensions':
              iter_series = source.data.series
  
          # Is 'data' a flat dataset with just a list of obs?
          if dim_at_obs == 'AllDimensions':
              obs_zip = iter(zip(*source.data.obs()))
              dimensions = next(obs_zip)
              idx = PD.MultiIndex.from_tuples(
                  dimensions, names=dimensions[0]._fields)
              if dtype:
                  values_series = PD.Series(
                      next(obs_zip), dtype=dtype, index=idx)
              if attributes:
                  obs_attrib = NP.asarray(next(obs_zip), dtype='object')
                  attrib_series = PD.Series(
                      obs_attrib, dtype='object', index=idx)
              # Decide what to return
              if dtype and attributes:
                  return values_series, attrib_series
              elif dtype:
                  return values_series
              elif attributes:
                  return attrib_series
  
          # So dataset has series:
          else:
              if asframe:
                  series_list = list(s for s in self.iter_pd_series(
                      iter_series, dim_at_obs, dtype, attributes,
                      reverse_obs, fromfreq, parse_time))
                  if dtype and attributes:
                      # series_list is actually a list of pairs of series
                      # containing data and metadata respectively
                      key_fields = series_list[0][0].name._fields
                      pd_series, pd_attributes = zip(*series_list)
                  elif dtype:
                      key_fields = series_list[0].name._fields
                      pd_series = series_list
                  elif attributes:
                      key_fields = series_list[0].name._fields
                      pd_attributes = series_list
  
                  if dtype:
                      # Merge series into multi-indexed DataFrame and return it.
                      d_frame = PD.concat(list(pd_series), axis=1, copy=False)
                      d_frame.columns.set_names(key_fields, inplace=True)
  
                  if attributes:
                      a_frame = PD.concat(pd_attributes, axis=1, copy=False)
                      a_frame.columns.set_names(key_fields, inplace=True)
                  # decide what to return
                  if dtype and attributes:
                      return d_frame, a_frame
                  elif dtype:
                      return d_frame
                  else:
                      return a_frame
  
              # return an iterator
              else:
                  return self.iter_pd_series(iter_series, dim_at_obs, dtype,
                                             attributes, reverse_obs, fromfreq, parse_time)